@decipher-sdk/decipher-qa 0.0.5 → 0.1.0
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/package.json +1 -1
- package/dist/index.js +0 -870
package/package.json
CHANGED
package/dist/index.js
DELETED
|
@@ -1,870 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";var fi=Object.create;var Ue=Object.defineProperty;var gi=Object.getOwnPropertyDescriptor;var yi=Object.getOwnPropertyNames;var bi=Object.getPrototypeOf,wi=Object.prototype.hasOwnProperty;var b=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports);var ki=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of yi(e))!wi.call(n,s)&&s!==t&&Ue(n,s,{get:()=>e[s],enumerable:!(i=gi(e,s))||i.enumerable});return n};var C=(n,e,t)=>(t=n!=null?fi(bi(n)):{},ki(e||!n||!n.__esModule?Ue(t,"default",{value:n,enumerable:!0}):t,n));var B=b(oe=>{"use strict";var J=class extends Error{constructor(e,t,i){super(i),Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.code=t,this.exitCode=e,this.nestedError=void 0}},re=class extends J{constructor(e){super(1,"commander.invalidArgument",e),Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name}};oe.CommanderError=J;oe.InvalidArgumentError=re});var z=b(le=>{"use strict";var{InvalidArgumentError:Ci}=B(),ae=class{constructor(e,t){switch(this.description=t||"",this.variadic=!1,this.parseArg=void 0,this.defaultValue=void 0,this.defaultValueDescription=void 0,this.argChoices=void 0,e[0]){case"<":this.required=!0,this._name=e.slice(1,-1);break;case"[":this.required=!1,this._name=e.slice(1,-1);break;default:this.required=!0,this._name=e;break}this._name.length>3&&this._name.slice(-3)==="..."&&(this.variadic=!0,this._name=this._name.slice(0,-3))}name(){return this._name}_concatValue(e,t){return t===this.defaultValue||!Array.isArray(t)?[e]:t.concat(e)}default(e,t){return this.defaultValue=e,this.defaultValueDescription=t,this}argParser(e){return this.parseArg=e,this}choices(e){return this.argChoices=e.slice(),this.parseArg=(t,i)=>{if(!this.argChoices.includes(t))throw new Ci(`Allowed choices are ${this.argChoices.join(", ")}.`);return this.variadic?this._concatValue(t,i):t},this}argRequired(){return this.required=!0,this}argOptional(){return this.required=!1,this}};function vi(n){let e=n.name()+(n.variadic===!0?"...":"");return n.required?"<"+e+">":"["+e+"]"}le.Argument=ae;le.humanReadableArgName=vi});var de=b(Le=>{"use strict";var{humanReadableArgName:_i}=z(),ce=class{constructor(){this.helpWidth=void 0,this.sortSubcommands=!1,this.sortOptions=!1,this.showGlobalOptions=!1}visibleCommands(e){let t=e.commands.filter(s=>!s._hidden),i=e._getHelpCommand();return i&&!i._hidden&&t.push(i),this.sortSubcommands&&t.sort((s,r)=>s.name().localeCompare(r.name())),t}compareOptions(e,t){let i=s=>s.short?s.short.replace(/^-/,""):s.long.replace(/^--/,"");return i(e).localeCompare(i(t))}visibleOptions(e){let t=e.options.filter(s=>!s.hidden),i=e._getHelpOption();if(i&&!i.hidden){let s=i.short&&e._findOption(i.short),r=i.long&&e._findOption(i.long);!s&&!r?t.push(i):i.long&&!r?t.push(e.createOption(i.long,i.description)):i.short&&!s&&t.push(e.createOption(i.short,i.description))}return this.sortOptions&&t.sort(this.compareOptions),t}visibleGlobalOptions(e){if(!this.showGlobalOptions)return[];let t=[];for(let i=e.parent;i;i=i.parent){let s=i.options.filter(r=>!r.hidden);t.push(...s)}return this.sortOptions&&t.sort(this.compareOptions),t}visibleArguments(e){return e._argsDescription&&e.registeredArguments.forEach(t=>{t.description=t.description||e._argsDescription[t.name()]||""}),e.registeredArguments.find(t=>t.description)?e.registeredArguments:[]}subcommandTerm(e){let t=e.registeredArguments.map(i=>_i(i)).join(" ");return e._name+(e._aliases[0]?"|"+e._aliases[0]:"")+(e.options.length?" [options]":"")+(t?" "+t:"")}optionTerm(e){return e.flags}argumentTerm(e){return e.name()}longestSubcommandTermLength(e,t){return t.visibleCommands(e).reduce((i,s)=>Math.max(i,t.subcommandTerm(s).length),0)}longestOptionTermLength(e,t){return t.visibleOptions(e).reduce((i,s)=>Math.max(i,t.optionTerm(s).length),0)}longestGlobalOptionTermLength(e,t){return t.visibleGlobalOptions(e).reduce((i,s)=>Math.max(i,t.optionTerm(s).length),0)}longestArgumentTermLength(e,t){return t.visibleArguments(e).reduce((i,s)=>Math.max(i,t.argumentTerm(s).length),0)}commandUsage(e){let t=e._name;e._aliases[0]&&(t=t+"|"+e._aliases[0]);let i="";for(let s=e.parent;s;s=s.parent)i=s.name()+" "+i;return i+t+" "+e.usage()}commandDescription(e){return e.description()}subcommandDescription(e){return e.summary()||e.description()}optionDescription(e){let t=[];return e.argChoices&&t.push(`choices: ${e.argChoices.map(i=>JSON.stringify(i)).join(", ")}`),e.defaultValue!==void 0&&(e.required||e.optional||e.isBoolean()&&typeof e.defaultValue=="boolean")&&t.push(`default: ${e.defaultValueDescription||JSON.stringify(e.defaultValue)}`),e.presetArg!==void 0&&e.optional&&t.push(`preset: ${JSON.stringify(e.presetArg)}`),e.envVar!==void 0&&t.push(`env: ${e.envVar}`),t.length>0?`${e.description} (${t.join(", ")})`:e.description}argumentDescription(e){let t=[];if(e.argChoices&&t.push(`choices: ${e.argChoices.map(i=>JSON.stringify(i)).join(", ")}`),e.defaultValue!==void 0&&t.push(`default: ${e.defaultValueDescription||JSON.stringify(e.defaultValue)}`),t.length>0){let i=`(${t.join(", ")})`;return e.description?`${e.description} ${i}`:i}return e.description}formatHelp(e,t){let i=t.padWidth(e,t),s=t.helpWidth||80,r=2,o=2;function a(g,T){if(T){let se=`${g.padEnd(i+o)}${T}`;return t.wrap(se,s-r,i+o)}return g}function l(g){return g.join(`
|
|
3
|
-
`).replace(/^/gm," ".repeat(r))}let c=[`Usage: ${t.commandUsage(e)}`,""],h=t.commandDescription(e);h.length>0&&(c=c.concat([t.wrap(h,s,0),""]));let p=t.visibleArguments(e).map(g=>a(t.argumentTerm(g),t.argumentDescription(g)));p.length>0&&(c=c.concat(["Arguments:",l(p),""]));let k=t.visibleOptions(e).map(g=>a(t.optionTerm(g),t.optionDescription(g)));if(k.length>0&&(c=c.concat(["Options:",l(k),""])),this.showGlobalOptions){let g=t.visibleGlobalOptions(e).map(T=>a(t.optionTerm(T),t.optionDescription(T)));g.length>0&&(c=c.concat(["Global Options:",l(g),""]))}let U=t.visibleCommands(e).map(g=>a(t.subcommandTerm(g),t.subcommandDescription(g)));return U.length>0&&(c=c.concat(["Commands:",l(U),""])),c.join(`
|
|
4
|
-
`)}padWidth(e,t){return Math.max(t.longestOptionTermLength(e,t),t.longestGlobalOptionTermLength(e,t),t.longestSubcommandTermLength(e,t),t.longestArgumentTermLength(e,t))}wrap(e,t,i,s=40){let r=" \\f\\t\\v\xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF",o=new RegExp(`[\\n][${r}]+`);if(e.match(o))return e;let a=t-i;if(a<s)return e;let l=e.slice(0,i),c=e.slice(i).replace(`\r
|
|
5
|
-
`,`
|
|
6
|
-
`),h=" ".repeat(i),k="\\s\u200B",U=new RegExp(`
|
|
7
|
-
|.{1,${a-1}}([${k}]|$)|[^${k}]+?([${k}]|$)`,"g"),g=c.match(U)||[];return l+g.map((T,se)=>T===`
|
|
8
|
-
`?"":(se>0?h:"")+T.trimEnd()).join(`
|
|
9
|
-
`)}};Le.Help=ce});var me=b(pe=>{"use strict";var{InvalidArgumentError:Ai}=B(),he=class{constructor(e,t){this.flags=e,this.description=t||"",this.required=e.includes("<"),this.optional=e.includes("["),this.variadic=/\w\.\.\.[>\]]$/.test(e),this.mandatory=!1;let i=Si(e);this.short=i.shortFlag,this.long=i.longFlag,this.negate=!1,this.long&&(this.negate=this.long.startsWith("--no-")),this.defaultValue=void 0,this.defaultValueDescription=void 0,this.presetArg=void 0,this.envVar=void 0,this.parseArg=void 0,this.hidden=!1,this.argChoices=void 0,this.conflictsWith=[],this.implied=void 0}default(e,t){return this.defaultValue=e,this.defaultValueDescription=t,this}preset(e){return this.presetArg=e,this}conflicts(e){return this.conflictsWith=this.conflictsWith.concat(e),this}implies(e){let t=e;return typeof e=="string"&&(t={[e]:!0}),this.implied=Object.assign(this.implied||{},t),this}env(e){return this.envVar=e,this}argParser(e){return this.parseArg=e,this}makeOptionMandatory(e=!0){return this.mandatory=!!e,this}hideHelp(e=!0){return this.hidden=!!e,this}_concatValue(e,t){return t===this.defaultValue||!Array.isArray(t)?[e]:t.concat(e)}choices(e){return this.argChoices=e.slice(),this.parseArg=(t,i)=>{if(!this.argChoices.includes(t))throw new Ai(`Allowed choices are ${this.argChoices.join(", ")}.`);return this.variadic?this._concatValue(t,i):t},this}name(){return this.long?this.long.replace(/^--/,""):this.short.replace(/^-/,"")}attributeName(){return Oi(this.name().replace(/^no-/,""))}is(e){return this.short===e||this.long===e}isBoolean(){return!this.required&&!this.optional&&!this.negate}},ue=class{constructor(e){this.positiveOptions=new Map,this.negativeOptions=new Map,this.dualOptions=new Set,e.forEach(t=>{t.negate?this.negativeOptions.set(t.attributeName(),t):this.positiveOptions.set(t.attributeName(),t)}),this.negativeOptions.forEach((t,i)=>{this.positiveOptions.has(i)&&this.dualOptions.add(i)})}valueFromOption(e,t){let i=t.attributeName();if(!this.dualOptions.has(i))return!0;let s=this.negativeOptions.get(i).presetArg,r=s!==void 0?s:!1;return t.negate===(r===e)}};function Oi(n){return n.split("-").reduce((e,t)=>e+t[0].toUpperCase()+t.slice(1))}function Si(n){let e,t,i=n.split(/[ |,]+/);return i.length>1&&!/^[[<]/.test(i[1])&&(e=i.shift()),t=i.shift(),!e&&/^-[^-]$/.test(t)&&(e=t,t=void 0),{shortFlag:e,longFlag:t}}pe.Option=he;pe.DualOptions=ue});var Me=b($e=>{"use strict";function xi(n,e){if(Math.abs(n.length-e.length)>3)return Math.max(n.length,e.length);let t=[];for(let i=0;i<=n.length;i++)t[i]=[i];for(let i=0;i<=e.length;i++)t[0][i]=i;for(let i=1;i<=e.length;i++)for(let s=1;s<=n.length;s++){let r=1;n[s-1]===e[i-1]?r=0:r=1,t[s][i]=Math.min(t[s-1][i]+1,t[s][i-1]+1,t[s-1][i-1]+r),s>1&&i>1&&n[s-1]===e[i-2]&&n[s-2]===e[i-1]&&(t[s][i]=Math.min(t[s][i],t[s-2][i-2]+1))}return t[n.length][e.length]}function Ii(n,e){if(!e||e.length===0)return"";e=Array.from(new Set(e));let t=n.startsWith("--");t&&(n=n.slice(2),e=e.map(o=>o.slice(2)));let i=[],s=3,r=.4;return e.forEach(o=>{if(o.length<=1)return;let a=xi(n,o),l=Math.max(n.length,o.length);(l-a)/l>r&&(a<s?(s=a,i=[o]):a===s&&i.push(o))}),i.sort((o,a)=>o.localeCompare(a)),t&&(i=i.map(o=>`--${o}`)),i.length>1?`
|
|
10
|
-
(Did you mean one of ${i.join(", ")}?)`:i.length===1?`
|
|
11
|
-
(Did you mean ${i[0]}?)`:""}$e.suggestSimilar=Ii});var Be=b(He=>{"use strict";var Ei=require("events").EventEmitter,fe=require("child_process"),I=require("path"),ge=require("fs"),f=require("process"),{Argument:qi,humanReadableArgName:Ti}=z(),{CommanderError:ye}=B(),{Help:Ni}=de(),{Option:Ve,DualOptions:Ri}=me(),{suggestSimilar:Fe}=Me(),be=class n extends Ei{constructor(e){super(),this.commands=[],this.options=[],this.parent=null,this._allowUnknownOption=!1,this._allowExcessArguments=!0,this.registeredArguments=[],this._args=this.registeredArguments,this.args=[],this.rawArgs=[],this.processedArgs=[],this._scriptPath=null,this._name=e||"",this._optionValues={},this._optionValueSources={},this._storeOptionsAsProperties=!1,this._actionHandler=null,this._executableHandler=!1,this._executableFile=null,this._executableDir=null,this._defaultCommandName=null,this._exitCallback=null,this._aliases=[],this._combineFlagAndOptionalValue=!0,this._description="",this._summary="",this._argsDescription=void 0,this._enablePositionalOptions=!1,this._passThroughOptions=!1,this._lifeCycleHooks={},this._showHelpAfterError=!1,this._showSuggestionAfterError=!0,this._outputConfiguration={writeOut:t=>f.stdout.write(t),writeErr:t=>f.stderr.write(t),getOutHelpWidth:()=>f.stdout.isTTY?f.stdout.columns:void 0,getErrHelpWidth:()=>f.stderr.isTTY?f.stderr.columns:void 0,outputError:(t,i)=>i(t)},this._hidden=!1,this._helpOption=void 0,this._addImplicitHelpCommand=void 0,this._helpCommand=void 0,this._helpConfiguration={}}copyInheritedSettings(e){return this._outputConfiguration=e._outputConfiguration,this._helpOption=e._helpOption,this._helpCommand=e._helpCommand,this._helpConfiguration=e._helpConfiguration,this._exitCallback=e._exitCallback,this._storeOptionsAsProperties=e._storeOptionsAsProperties,this._combineFlagAndOptionalValue=e._combineFlagAndOptionalValue,this._allowExcessArguments=e._allowExcessArguments,this._enablePositionalOptions=e._enablePositionalOptions,this._showHelpAfterError=e._showHelpAfterError,this._showSuggestionAfterError=e._showSuggestionAfterError,this}_getCommandAndAncestors(){let e=[];for(let t=this;t;t=t.parent)e.push(t);return e}command(e,t,i){let s=t,r=i;typeof s=="object"&&s!==null&&(r=s,s=null),r=r||{};let[,o,a]=e.match(/([^ ]+) *(.*)/),l=this.createCommand(o);return s&&(l.description(s),l._executableHandler=!0),r.isDefault&&(this._defaultCommandName=l._name),l._hidden=!!(r.noHelp||r.hidden),l._executableFile=r.executableFile||null,a&&l.arguments(a),this._registerCommand(l),l.parent=this,l.copyInheritedSettings(this),s?this:l}createCommand(e){return new n(e)}createHelp(){return Object.assign(new Ni,this.configureHelp())}configureHelp(e){return e===void 0?this._helpConfiguration:(this._helpConfiguration=e,this)}configureOutput(e){return e===void 0?this._outputConfiguration:(Object.assign(this._outputConfiguration,e),this)}showHelpAfterError(e=!0){return typeof e!="string"&&(e=!!e),this._showHelpAfterError=e,this}showSuggestionAfterError(e=!0){return this._showSuggestionAfterError=!!e,this}addCommand(e,t){if(!e._name)throw new Error(`Command passed to .addCommand() must have a name
|
|
12
|
-
- specify the name in Command constructor or using .name()`);return t=t||{},t.isDefault&&(this._defaultCommandName=e._name),(t.noHelp||t.hidden)&&(e._hidden=!0),this._registerCommand(e),e.parent=this,e._checkForBrokenPassThrough(),this}createArgument(e,t){return new qi(e,t)}argument(e,t,i,s){let r=this.createArgument(e,t);return typeof i=="function"?r.default(s).argParser(i):r.default(i),this.addArgument(r),this}arguments(e){return e.trim().split(/ +/).forEach(t=>{this.argument(t)}),this}addArgument(e){let t=this.registeredArguments.slice(-1)[0];if(t&&t.variadic)throw new Error(`only the last argument can be variadic '${t.name()}'`);if(e.required&&e.defaultValue!==void 0&&e.parseArg===void 0)throw new Error(`a default value for a required argument is never used: '${e.name()}'`);return this.registeredArguments.push(e),this}helpCommand(e,t){if(typeof e=="boolean")return this._addImplicitHelpCommand=e,this;e=e??"help [command]";let[,i,s]=e.match(/([^ ]+) *(.*)/),r=t??"display help for command",o=this.createCommand(i);return o.helpOption(!1),s&&o.arguments(s),r&&o.description(r),this._addImplicitHelpCommand=!0,this._helpCommand=o,this}addHelpCommand(e,t){return typeof e!="object"?(this.helpCommand(e,t),this):(this._addImplicitHelpCommand=!0,this._helpCommand=e,this)}_getHelpCommand(){return this._addImplicitHelpCommand??(this.commands.length&&!this._actionHandler&&!this._findCommand("help"))?(this._helpCommand===void 0&&this.helpCommand(void 0,void 0),this._helpCommand):null}hook(e,t){let i=["preSubcommand","preAction","postAction"];if(!i.includes(e))throw new Error(`Unexpected value for event passed to hook : '${e}'.
|
|
13
|
-
Expecting one of '${i.join("', '")}'`);return this._lifeCycleHooks[e]?this._lifeCycleHooks[e].push(t):this._lifeCycleHooks[e]=[t],this}exitOverride(e){return e?this._exitCallback=e:this._exitCallback=t=>{if(t.code!=="commander.executeSubCommandAsync")throw t},this}_exit(e,t,i){this._exitCallback&&this._exitCallback(new ye(e,t,i)),f.exit(e)}action(e){let t=i=>{let s=this.registeredArguments.length,r=i.slice(0,s);return this._storeOptionsAsProperties?r[s]=this:r[s]=this.opts(),r.push(this),e.apply(this,r)};return this._actionHandler=t,this}createOption(e,t){return new Ve(e,t)}_callParseArg(e,t,i,s){try{return e.parseArg(t,i)}catch(r){if(r.code==="commander.invalidArgument"){let o=`${s} ${r.message}`;this.error(o,{exitCode:r.exitCode,code:r.code})}throw r}}_registerOption(e){let t=e.short&&this._findOption(e.short)||e.long&&this._findOption(e.long);if(t){let i=e.long&&this._findOption(e.long)?e.long:e.short;throw new Error(`Cannot add option '${e.flags}'${this._name&&` to command '${this._name}'`} due to conflicting flag '${i}'
|
|
14
|
-
- already used by option '${t.flags}'`)}this.options.push(e)}_registerCommand(e){let t=s=>[s.name()].concat(s.aliases()),i=t(e).find(s=>this._findCommand(s));if(i){let s=t(this._findCommand(i)).join("|"),r=t(e).join("|");throw new Error(`cannot add command '${r}' as already have command '${s}'`)}this.commands.push(e)}addOption(e){this._registerOption(e);let t=e.name(),i=e.attributeName();if(e.negate){let r=e.long.replace(/^--no-/,"--");this._findOption(r)||this.setOptionValueWithSource(i,e.defaultValue===void 0?!0:e.defaultValue,"default")}else e.defaultValue!==void 0&&this.setOptionValueWithSource(i,e.defaultValue,"default");let s=(r,o,a)=>{r==null&&e.presetArg!==void 0&&(r=e.presetArg);let l=this.getOptionValue(i);r!==null&&e.parseArg?r=this._callParseArg(e,r,l,o):r!==null&&e.variadic&&(r=e._concatValue(r,l)),r==null&&(e.negate?r=!1:e.isBoolean()||e.optional?r=!0:r=""),this.setOptionValueWithSource(i,r,a)};return this.on("option:"+t,r=>{let o=`error: option '${e.flags}' argument '${r}' is invalid.`;s(r,o,"cli")}),e.envVar&&this.on("optionEnv:"+t,r=>{let o=`error: option '${e.flags}' value '${r}' from env '${e.envVar}' is invalid.`;s(r,o,"env")}),this}_optionEx(e,t,i,s,r){if(typeof t=="object"&&t instanceof Ve)throw new Error("To add an Option object use addOption() instead of option() or requiredOption()");let o=this.createOption(t,i);if(o.makeOptionMandatory(!!e.mandatory),typeof s=="function")o.default(r).argParser(s);else if(s instanceof RegExp){let a=s;s=(l,c)=>{let h=a.exec(l);return h?h[0]:c},o.default(r).argParser(s)}else o.default(s);return this.addOption(o)}option(e,t,i,s){return this._optionEx({},e,t,i,s)}requiredOption(e,t,i,s){return this._optionEx({mandatory:!0},e,t,i,s)}combineFlagAndOptionalValue(e=!0){return this._combineFlagAndOptionalValue=!!e,this}allowUnknownOption(e=!0){return this._allowUnknownOption=!!e,this}allowExcessArguments(e=!0){return this._allowExcessArguments=!!e,this}enablePositionalOptions(e=!0){return this._enablePositionalOptions=!!e,this}passThroughOptions(e=!0){return this._passThroughOptions=!!e,this._checkForBrokenPassThrough(),this}_checkForBrokenPassThrough(){if(this.parent&&this._passThroughOptions&&!this.parent._enablePositionalOptions)throw new Error(`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`)}storeOptionsAsProperties(e=!0){if(this.options.length)throw new Error("call .storeOptionsAsProperties() before adding options");if(Object.keys(this._optionValues).length)throw new Error("call .storeOptionsAsProperties() before setting option values");return this._storeOptionsAsProperties=!!e,this}getOptionValue(e){return this._storeOptionsAsProperties?this[e]:this._optionValues[e]}setOptionValue(e,t){return this.setOptionValueWithSource(e,t,void 0)}setOptionValueWithSource(e,t,i){return this._storeOptionsAsProperties?this[e]=t:this._optionValues[e]=t,this._optionValueSources[e]=i,this}getOptionValueSource(e){return this._optionValueSources[e]}getOptionValueSourceWithGlobals(e){let t;return this._getCommandAndAncestors().forEach(i=>{i.getOptionValueSource(e)!==void 0&&(t=i.getOptionValueSource(e))}),t}_prepareUserArgs(e,t){if(e!==void 0&&!Array.isArray(e))throw new Error("first parameter to parse must be array or undefined");if(t=t||{},e===void 0&&t.from===void 0){f.versions?.electron&&(t.from="electron");let s=f.execArgv??[];(s.includes("-e")||s.includes("--eval")||s.includes("-p")||s.includes("--print"))&&(t.from="eval")}e===void 0&&(e=f.argv),this.rawArgs=e.slice();let i;switch(t.from){case void 0:case"node":this._scriptPath=e[1],i=e.slice(2);break;case"electron":f.defaultApp?(this._scriptPath=e[1],i=e.slice(2)):i=e.slice(1);break;case"user":i=e.slice(0);break;case"eval":i=e.slice(1);break;default:throw new Error(`unexpected parse option { from: '${t.from}' }`)}return!this._name&&this._scriptPath&&this.nameFromFilename(this._scriptPath),this._name=this._name||"program",i}parse(e,t){let i=this._prepareUserArgs(e,t);return this._parseCommand([],i),this}async parseAsync(e,t){let i=this._prepareUserArgs(e,t);return await this._parseCommand([],i),this}_executeSubCommand(e,t){t=t.slice();let i=!1,s=[".js",".ts",".tsx",".mjs",".cjs"];function r(h,p){let k=I.resolve(h,p);if(ge.existsSync(k))return k;if(s.includes(I.extname(p)))return;let U=s.find(g=>ge.existsSync(`${k}${g}`));if(U)return`${k}${U}`}this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let o=e._executableFile||`${this._name}-${e._name}`,a=this._executableDir||"";if(this._scriptPath){let h;try{h=ge.realpathSync(this._scriptPath)}catch{h=this._scriptPath}a=I.resolve(I.dirname(h),a)}if(a){let h=r(a,o);if(!h&&!e._executableFile&&this._scriptPath){let p=I.basename(this._scriptPath,I.extname(this._scriptPath));p!==this._name&&(h=r(a,`${p}-${e._name}`))}o=h||o}i=s.includes(I.extname(o));let l;f.platform!=="win32"?i?(t.unshift(o),t=je(f.execArgv).concat(t),l=fe.spawn(f.argv[0],t,{stdio:"inherit"})):l=fe.spawn(o,t,{stdio:"inherit"}):(t.unshift(o),t=je(f.execArgv).concat(t),l=fe.spawn(f.execPath,t,{stdio:"inherit"})),l.killed||["SIGUSR1","SIGUSR2","SIGTERM","SIGINT","SIGHUP"].forEach(p=>{f.on(p,()=>{l.killed===!1&&l.exitCode===null&&l.kill(p)})});let c=this._exitCallback;l.on("close",h=>{h=h??1,c?c(new ye(h,"commander.executeSubCommandAsync","(close)")):f.exit(h)}),l.on("error",h=>{if(h.code==="ENOENT"){let p=a?`searched for local subcommand relative to directory '${a}'`:"no directory for search for local subcommand, use .executableDir() to supply a custom directory",k=`'${o}' does not exist
|
|
15
|
-
- if '${e._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
16
|
-
- if the default executable name is not suitable, use the executableFile option to supply a custom name or path
|
|
17
|
-
- ${p}`;throw new Error(k)}else if(h.code==="EACCES")throw new Error(`'${o}' not executable`);if(!c)f.exit(1);else{let p=new ye(1,"commander.executeSubCommandAsync","(error)");p.nestedError=h,c(p)}}),this.runningCommand=l}_dispatchSubcommand(e,t,i){let s=this._findCommand(e);s||this.help({error:!0});let r;return r=this._chainOrCallSubCommandHook(r,s,"preSubcommand"),r=this._chainOrCall(r,()=>{if(s._executableHandler)this._executeSubCommand(s,t.concat(i));else return s._parseCommand(t,i)}),r}_dispatchHelpCommand(e){e||this.help();let t=this._findCommand(e);return t&&!t._executableHandler&&t.help(),this._dispatchSubcommand(e,[],[this._getHelpOption()?.long??this._getHelpOption()?.short??"--help"])}_checkNumberOfArguments(){this.registeredArguments.forEach((e,t)=>{e.required&&this.args[t]==null&&this.missingArgument(e.name())}),!(this.registeredArguments.length>0&&this.registeredArguments[this.registeredArguments.length-1].variadic)&&this.args.length>this.registeredArguments.length&&this._excessArguments(this.args)}_processArguments(){let e=(i,s,r)=>{let o=s;if(s!==null&&i.parseArg){let a=`error: command-argument value '${s}' is invalid for argument '${i.name()}'.`;o=this._callParseArg(i,s,r,a)}return o};this._checkNumberOfArguments();let t=[];this.registeredArguments.forEach((i,s)=>{let r=i.defaultValue;i.variadic?s<this.args.length?(r=this.args.slice(s),i.parseArg&&(r=r.reduce((o,a)=>e(i,a,o),i.defaultValue))):r===void 0&&(r=[]):s<this.args.length&&(r=this.args[s],i.parseArg&&(r=e(i,r,i.defaultValue))),t[s]=r}),this.processedArgs=t}_chainOrCall(e,t){return e&&e.then&&typeof e.then=="function"?e.then(()=>t()):t()}_chainOrCallHooks(e,t){let i=e,s=[];return this._getCommandAndAncestors().reverse().filter(r=>r._lifeCycleHooks[t]!==void 0).forEach(r=>{r._lifeCycleHooks[t].forEach(o=>{s.push({hookedCommand:r,callback:o})})}),t==="postAction"&&s.reverse(),s.forEach(r=>{i=this._chainOrCall(i,()=>r.callback(r.hookedCommand,this))}),i}_chainOrCallSubCommandHook(e,t,i){let s=e;return this._lifeCycleHooks[i]!==void 0&&this._lifeCycleHooks[i].forEach(r=>{s=this._chainOrCall(s,()=>r(this,t))}),s}_parseCommand(e,t){let i=this.parseOptions(t);if(this._parseOptionsEnv(),this._parseOptionsImplied(),e=e.concat(i.operands),t=i.unknown,this.args=e.concat(t),e&&this._findCommand(e[0]))return this._dispatchSubcommand(e[0],e.slice(1),t);if(this._getHelpCommand()&&e[0]===this._getHelpCommand().name())return this._dispatchHelpCommand(e[1]);if(this._defaultCommandName)return this._outputHelpIfRequested(t),this._dispatchSubcommand(this._defaultCommandName,e,t);this.commands.length&&this.args.length===0&&!this._actionHandler&&!this._defaultCommandName&&this.help({error:!0}),this._outputHelpIfRequested(i.unknown),this._checkForMissingMandatoryOptions(),this._checkForConflictingOptions();let s=()=>{i.unknown.length>0&&this.unknownOption(i.unknown[0])},r=`command:${this.name()}`;if(this._actionHandler){s(),this._processArguments();let o;return o=this._chainOrCallHooks(o,"preAction"),o=this._chainOrCall(o,()=>this._actionHandler(this.processedArgs)),this.parent&&(o=this._chainOrCall(o,()=>{this.parent.emit(r,e,t)})),o=this._chainOrCallHooks(o,"postAction"),o}if(this.parent&&this.parent.listenerCount(r))s(),this._processArguments(),this.parent.emit(r,e,t);else if(e.length){if(this._findCommand("*"))return this._dispatchSubcommand("*",e,t);this.listenerCount("command:*")?this.emit("command:*",e,t):this.commands.length?this.unknownCommand():(s(),this._processArguments())}else this.commands.length?(s(),this.help({error:!0})):(s(),this._processArguments())}_findCommand(e){if(e)return this.commands.find(t=>t._name===e||t._aliases.includes(e))}_findOption(e){return this.options.find(t=>t.is(e))}_checkForMissingMandatoryOptions(){this._getCommandAndAncestors().forEach(e=>{e.options.forEach(t=>{t.mandatory&&e.getOptionValue(t.attributeName())===void 0&&e.missingMandatoryOptionValue(t)})})}_checkForConflictingLocalOptions(){let e=this.options.filter(i=>{let s=i.attributeName();return this.getOptionValue(s)===void 0?!1:this.getOptionValueSource(s)!=="default"});e.filter(i=>i.conflictsWith.length>0).forEach(i=>{let s=e.find(r=>i.conflictsWith.includes(r.attributeName()));s&&this._conflictingOption(i,s)})}_checkForConflictingOptions(){this._getCommandAndAncestors().forEach(e=>{e._checkForConflictingLocalOptions()})}parseOptions(e){let t=[],i=[],s=t,r=e.slice();function o(l){return l.length>1&&l[0]==="-"}let a=null;for(;r.length;){let l=r.shift();if(l==="--"){s===i&&s.push(l),s.push(...r);break}if(a&&!o(l)){this.emit(`option:${a.name()}`,l);continue}if(a=null,o(l)){let c=this._findOption(l);if(c){if(c.required){let h=r.shift();h===void 0&&this.optionMissingArgument(c),this.emit(`option:${c.name()}`,h)}else if(c.optional){let h=null;r.length>0&&!o(r[0])&&(h=r.shift()),this.emit(`option:${c.name()}`,h)}else this.emit(`option:${c.name()}`);a=c.variadic?c:null;continue}}if(l.length>2&&l[0]==="-"&&l[1]!=="-"){let c=this._findOption(`-${l[1]}`);if(c){c.required||c.optional&&this._combineFlagAndOptionalValue?this.emit(`option:${c.name()}`,l.slice(2)):(this.emit(`option:${c.name()}`),r.unshift(`-${l.slice(2)}`));continue}}if(/^--[^=]+=/.test(l)){let c=l.indexOf("="),h=this._findOption(l.slice(0,c));if(h&&(h.required||h.optional)){this.emit(`option:${h.name()}`,l.slice(c+1));continue}}if(o(l)&&(s=i),(this._enablePositionalOptions||this._passThroughOptions)&&t.length===0&&i.length===0){if(this._findCommand(l)){t.push(l),r.length>0&&i.push(...r);break}else if(this._getHelpCommand()&&l===this._getHelpCommand().name()){t.push(l),r.length>0&&t.push(...r);break}else if(this._defaultCommandName){i.push(l),r.length>0&&i.push(...r);break}}if(this._passThroughOptions){s.push(l),r.length>0&&s.push(...r);break}s.push(l)}return{operands:t,unknown:i}}opts(){if(this._storeOptionsAsProperties){let e={},t=this.options.length;for(let i=0;i<t;i++){let s=this.options[i].attributeName();e[s]=s===this._versionOptionName?this._version:this[s]}return e}return this._optionValues}optsWithGlobals(){return this._getCommandAndAncestors().reduce((e,t)=>Object.assign(e,t.opts()),{})}error(e,t){this._outputConfiguration.outputError(`${e}
|
|
18
|
-
`,this._outputConfiguration.writeErr),typeof this._showHelpAfterError=="string"?this._outputConfiguration.writeErr(`${this._showHelpAfterError}
|
|
19
|
-
`):this._showHelpAfterError&&(this._outputConfiguration.writeErr(`
|
|
20
|
-
`),this.outputHelp({error:!0}));let i=t||{},s=i.exitCode||1,r=i.code||"commander.error";this._exit(s,r,e)}_parseOptionsEnv(){this.options.forEach(e=>{if(e.envVar&&e.envVar in f.env){let t=e.attributeName();(this.getOptionValue(t)===void 0||["default","config","env"].includes(this.getOptionValueSource(t)))&&(e.required||e.optional?this.emit(`optionEnv:${e.name()}`,f.env[e.envVar]):this.emit(`optionEnv:${e.name()}`))}})}_parseOptionsImplied(){let e=new Ri(this.options),t=i=>this.getOptionValue(i)!==void 0&&!["default","implied"].includes(this.getOptionValueSource(i));this.options.filter(i=>i.implied!==void 0&&t(i.attributeName())&&e.valueFromOption(this.getOptionValue(i.attributeName()),i)).forEach(i=>{Object.keys(i.implied).filter(s=>!t(s)).forEach(s=>{this.setOptionValueWithSource(s,i.implied[s],"implied")})})}missingArgument(e){let t=`error: missing required argument '${e}'`;this.error(t,{code:"commander.missingArgument"})}optionMissingArgument(e){let t=`error: option '${e.flags}' argument missing`;this.error(t,{code:"commander.optionMissingArgument"})}missingMandatoryOptionValue(e){let t=`error: required option '${e.flags}' not specified`;this.error(t,{code:"commander.missingMandatoryOptionValue"})}_conflictingOption(e,t){let i=o=>{let a=o.attributeName(),l=this.getOptionValue(a),c=this.options.find(p=>p.negate&&a===p.attributeName()),h=this.options.find(p=>!p.negate&&a===p.attributeName());return c&&(c.presetArg===void 0&&l===!1||c.presetArg!==void 0&&l===c.presetArg)?c:h||o},s=o=>{let a=i(o),l=a.attributeName();return this.getOptionValueSource(l)==="env"?`environment variable '${a.envVar}'`:`option '${a.flags}'`},r=`error: ${s(e)} cannot be used with ${s(t)}`;this.error(r,{code:"commander.conflictingOption"})}unknownOption(e){if(this._allowUnknownOption)return;let t="";if(e.startsWith("--")&&this._showSuggestionAfterError){let s=[],r=this;do{let o=r.createHelp().visibleOptions(r).filter(a=>a.long).map(a=>a.long);s=s.concat(o),r=r.parent}while(r&&!r._enablePositionalOptions);t=Fe(e,s)}let i=`error: unknown option '${e}'${t}`;this.error(i,{code:"commander.unknownOption"})}_excessArguments(e){if(this._allowExcessArguments)return;let t=this.registeredArguments.length,i=t===1?"":"s",r=`error: too many arguments${this.parent?` for '${this.name()}'`:""}. Expected ${t} argument${i} but got ${e.length}.`;this.error(r,{code:"commander.excessArguments"})}unknownCommand(){let e=this.args[0],t="";if(this._showSuggestionAfterError){let s=[];this.createHelp().visibleCommands(this).forEach(r=>{s.push(r.name()),r.alias()&&s.push(r.alias())}),t=Fe(e,s)}let i=`error: unknown command '${e}'${t}`;this.error(i,{code:"commander.unknownCommand"})}version(e,t,i){if(e===void 0)return this._version;this._version=e,t=t||"-V, --version",i=i||"output the version number";let s=this.createOption(t,i);return this._versionOptionName=s.attributeName(),this._registerOption(s),this.on("option:"+s.name(),()=>{this._outputConfiguration.writeOut(`${e}
|
|
21
|
-
`),this._exit(0,"commander.version",e)}),this}description(e,t){return e===void 0&&t===void 0?this._description:(this._description=e,t&&(this._argsDescription=t),this)}summary(e){return e===void 0?this._summary:(this._summary=e,this)}alias(e){if(e===void 0)return this._aliases[0];let t=this;if(this.commands.length!==0&&this.commands[this.commands.length-1]._executableHandler&&(t=this.commands[this.commands.length-1]),e===t._name)throw new Error("Command alias can't be the same as its name");let i=this.parent?._findCommand(e);if(i){let s=[i.name()].concat(i.aliases()).join("|");throw new Error(`cannot add alias '${e}' to command '${this.name()}' as already have command '${s}'`)}return t._aliases.push(e),this}aliases(e){return e===void 0?this._aliases:(e.forEach(t=>this.alias(t)),this)}usage(e){if(e===void 0){if(this._usage)return this._usage;let t=this.registeredArguments.map(i=>Ti(i));return[].concat(this.options.length||this._helpOption!==null?"[options]":[],this.commands.length?"[command]":[],this.registeredArguments.length?t:[]).join(" ")}return this._usage=e,this}name(e){return e===void 0?this._name:(this._name=e,this)}nameFromFilename(e){return this._name=I.basename(e,I.extname(e)),this}executableDir(e){return e===void 0?this._executableDir:(this._executableDir=e,this)}helpInformation(e){let t=this.createHelp();return t.helpWidth===void 0&&(t.helpWidth=e&&e.error?this._outputConfiguration.getErrHelpWidth():this._outputConfiguration.getOutHelpWidth()),t.formatHelp(this,t)}_getHelpContext(e){e=e||{};let t={error:!!e.error},i;return t.error?i=s=>this._outputConfiguration.writeErr(s):i=s=>this._outputConfiguration.writeOut(s),t.write=e.write||i,t.command=this,t}outputHelp(e){let t;typeof e=="function"&&(t=e,e=void 0);let i=this._getHelpContext(e);this._getCommandAndAncestors().reverse().forEach(r=>r.emit("beforeAllHelp",i)),this.emit("beforeHelp",i);let s=this.helpInformation(i);if(t&&(s=t(s),typeof s!="string"&&!Buffer.isBuffer(s)))throw new Error("outputHelp callback must return a string or a Buffer");i.write(s),this._getHelpOption()?.long&&this.emit(this._getHelpOption().long),this.emit("afterHelp",i),this._getCommandAndAncestors().forEach(r=>r.emit("afterAllHelp",i))}helpOption(e,t){return typeof e=="boolean"?(e?this._helpOption=this._helpOption??void 0:this._helpOption=null,this):(e=e??"-h, --help",t=t??"display help for command",this._helpOption=this.createOption(e,t),this)}_getHelpOption(){return this._helpOption===void 0&&this.helpOption(void 0,void 0),this._helpOption}addHelpOption(e){return this._helpOption=e,this}help(e){this.outputHelp(e);let t=f.exitCode||0;t===0&&e&&typeof e!="function"&&e.error&&(t=1),this._exit(t,"commander.help","(outputHelp)")}addHelpText(e,t){let i=["beforeAll","before","after","afterAll"];if(!i.includes(e))throw new Error(`Unexpected value for position to addHelpText.
|
|
22
|
-
Expecting one of '${i.join("', '")}'`);let s=`${e}Help`;return this.on(s,r=>{let o;typeof t=="function"?o=t({error:r.error,command:r.command}):o=t,o&&r.write(`${o}
|
|
23
|
-
`)}),this}_outputHelpIfRequested(e){let t=this._getHelpOption();t&&e.find(s=>t.is(s))&&(this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)"))}};function je(n){return n.map(e=>{if(!e.startsWith("--inspect"))return e;let t,i="127.0.0.1",s="9229",r;return(r=e.match(/^(--inspect(-brk)?)$/))!==null?t=r[1]:(r=e.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))!==null?(t=r[1],/^\d+$/.test(r[3])?s=r[3]:i=r[3]):(r=e.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null&&(t=r[1],i=r[3],s=r[4]),t&&s!=="0"?`${t}=${i}:${parseInt(s)+1}`:e})}He.Command=be});var ze=b(O=>{"use strict";var{Argument:Ge}=z(),{Command:we}=Be(),{CommanderError:Pi,InvalidArgumentError:We}=B(),{Help:Di}=de(),{Option:Je}=me();O.program=new we;O.createCommand=n=>new we(n);O.createOption=(n,e)=>new Je(n,e);O.createArgument=(n,e)=>new Ge(n,e);O.Command=we;O.Option=Je;O.Argument=Ge;O.Help=Di;O.CommanderError=Pi;O.InvalidArgumentError=We;O.InvalidOptionArgumentError=We});var st=b((Mn,nt)=>{"use strict";nt.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}});var ke=b((Vn,ot)=>{"use strict";var G=st(),rt={};for(let n of Object.keys(G))rt[G[n]]=n;var d={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};ot.exports=d;for(let n of Object.keys(d)){if(!("channels"in d[n]))throw new Error("missing channels property: "+n);if(!("labels"in d[n]))throw new Error("missing channel labels property: "+n);if(d[n].labels.length!==d[n].channels)throw new Error("channel and label counts mismatch: "+n);let{channels:e,labels:t}=d[n];delete d[n].channels,delete d[n].labels,Object.defineProperty(d[n],"channels",{value:e}),Object.defineProperty(d[n],"labels",{value:t})}d.rgb.hsl=function(n){let e=n[0]/255,t=n[1]/255,i=n[2]/255,s=Math.min(e,t,i),r=Math.max(e,t,i),o=r-s,a,l;r===s?a=0:e===r?a=(t-i)/o:t===r?a=2+(i-e)/o:i===r&&(a=4+(e-t)/o),a=Math.min(a*60,360),a<0&&(a+=360);let c=(s+r)/2;return r===s?l=0:c<=.5?l=o/(r+s):l=o/(2-r-s),[a,l*100,c*100]};d.rgb.hsv=function(n){let e,t,i,s,r,o=n[0]/255,a=n[1]/255,l=n[2]/255,c=Math.max(o,a,l),h=c-Math.min(o,a,l),p=function(k){return(c-k)/6/h+1/2};return h===0?(s=0,r=0):(r=h/c,e=p(o),t=p(a),i=p(l),o===c?s=i-t:a===c?s=1/3+e-i:l===c&&(s=2/3+t-e),s<0?s+=1:s>1&&(s-=1)),[s*360,r*100,c*100]};d.rgb.hwb=function(n){let e=n[0],t=n[1],i=n[2],s=d.rgb.hsl(n)[0],r=1/255*Math.min(e,Math.min(t,i));return i=1-1/255*Math.max(e,Math.max(t,i)),[s,r*100,i*100]};d.rgb.cmyk=function(n){let e=n[0]/255,t=n[1]/255,i=n[2]/255,s=Math.min(1-e,1-t,1-i),r=(1-e-s)/(1-s)||0,o=(1-t-s)/(1-s)||0,a=(1-i-s)/(1-s)||0;return[r*100,o*100,a*100,s*100]};function Ui(n,e){return(n[0]-e[0])**2+(n[1]-e[1])**2+(n[2]-e[2])**2}d.rgb.keyword=function(n){let e=rt[n];if(e)return e;let t=1/0,i;for(let s of Object.keys(G)){let r=G[s],o=Ui(n,r);o<t&&(t=o,i=s)}return i};d.keyword.rgb=function(n){return G[n]};d.rgb.xyz=function(n){let e=n[0]/255,t=n[1]/255,i=n[2]/255;e=e>.04045?((e+.055)/1.055)**2.4:e/12.92,t=t>.04045?((t+.055)/1.055)**2.4:t/12.92,i=i>.04045?((i+.055)/1.055)**2.4:i/12.92;let s=e*.4124+t*.3576+i*.1805,r=e*.2126+t*.7152+i*.0722,o=e*.0193+t*.1192+i*.9505;return[s*100,r*100,o*100]};d.rgb.lab=function(n){let e=d.rgb.xyz(n),t=e[0],i=e[1],s=e[2];t/=95.047,i/=100,s/=108.883,t=t>.008856?t**(1/3):7.787*t+16/116,i=i>.008856?i**(1/3):7.787*i+16/116,s=s>.008856?s**(1/3):7.787*s+16/116;let r=116*i-16,o=500*(t-i),a=200*(i-s);return[r,o,a]};d.hsl.rgb=function(n){let e=n[0]/360,t=n[1]/100,i=n[2]/100,s,r,o;if(t===0)return o=i*255,[o,o,o];i<.5?s=i*(1+t):s=i+t-i*t;let a=2*i-s,l=[0,0,0];for(let c=0;c<3;c++)r=e+1/3*-(c-1),r<0&&r++,r>1&&r--,6*r<1?o=a+(s-a)*6*r:2*r<1?o=s:3*r<2?o=a+(s-a)*(2/3-r)*6:o=a,l[c]=o*255;return l};d.hsl.hsv=function(n){let e=n[0],t=n[1]/100,i=n[2]/100,s=t,r=Math.max(i,.01);i*=2,t*=i<=1?i:2-i,s*=r<=1?r:2-r;let o=(i+t)/2,a=i===0?2*s/(r+s):2*t/(i+t);return[e,a*100,o*100]};d.hsv.rgb=function(n){let e=n[0]/60,t=n[1]/100,i=n[2]/100,s=Math.floor(e)%6,r=e-Math.floor(e),o=255*i*(1-t),a=255*i*(1-t*r),l=255*i*(1-t*(1-r));switch(i*=255,s){case 0:return[i,l,o];case 1:return[a,i,o];case 2:return[o,i,l];case 3:return[o,a,i];case 4:return[l,o,i];case 5:return[i,o,a]}};d.hsv.hsl=function(n){let e=n[0],t=n[1]/100,i=n[2]/100,s=Math.max(i,.01),r,o;o=(2-t)*i;let a=(2-t)*s;return r=t*s,r/=a<=1?a:2-a,r=r||0,o/=2,[e,r*100,o*100]};d.hwb.rgb=function(n){let e=n[0]/360,t=n[1]/100,i=n[2]/100,s=t+i,r;s>1&&(t/=s,i/=s);let o=Math.floor(6*e),a=1-i;r=6*e-o,(o&1)!==0&&(r=1-r);let l=t+r*(a-t),c,h,p;switch(o){default:case 6:case 0:c=a,h=l,p=t;break;case 1:c=l,h=a,p=t;break;case 2:c=t,h=a,p=l;break;case 3:c=t,h=l,p=a;break;case 4:c=l,h=t,p=a;break;case 5:c=a,h=t,p=l;break}return[c*255,h*255,p*255]};d.cmyk.rgb=function(n){let e=n[0]/100,t=n[1]/100,i=n[2]/100,s=n[3]/100,r=1-Math.min(1,e*(1-s)+s),o=1-Math.min(1,t*(1-s)+s),a=1-Math.min(1,i*(1-s)+s);return[r*255,o*255,a*255]};d.xyz.rgb=function(n){let e=n[0]/100,t=n[1]/100,i=n[2]/100,s,r,o;return s=e*3.2406+t*-1.5372+i*-.4986,r=e*-.9689+t*1.8758+i*.0415,o=e*.0557+t*-.204+i*1.057,s=s>.0031308?1.055*s**(1/2.4)-.055:s*12.92,r=r>.0031308?1.055*r**(1/2.4)-.055:r*12.92,o=o>.0031308?1.055*o**(1/2.4)-.055:o*12.92,s=Math.min(Math.max(0,s),1),r=Math.min(Math.max(0,r),1),o=Math.min(Math.max(0,o),1),[s*255,r*255,o*255]};d.xyz.lab=function(n){let e=n[0],t=n[1],i=n[2];e/=95.047,t/=100,i/=108.883,e=e>.008856?e**(1/3):7.787*e+16/116,t=t>.008856?t**(1/3):7.787*t+16/116,i=i>.008856?i**(1/3):7.787*i+16/116;let s=116*t-16,r=500*(e-t),o=200*(t-i);return[s,r,o]};d.lab.xyz=function(n){let e=n[0],t=n[1],i=n[2],s,r,o;r=(e+16)/116,s=t/500+r,o=r-i/200;let a=r**3,l=s**3,c=o**3;return r=a>.008856?a:(r-16/116)/7.787,s=l>.008856?l:(s-16/116)/7.787,o=c>.008856?c:(o-16/116)/7.787,s*=95.047,r*=100,o*=108.883,[s,r,o]};d.lab.lch=function(n){let e=n[0],t=n[1],i=n[2],s;s=Math.atan2(i,t)*360/2/Math.PI,s<0&&(s+=360);let o=Math.sqrt(t*t+i*i);return[e,o,s]};d.lch.lab=function(n){let e=n[0],t=n[1],s=n[2]/360*2*Math.PI,r=t*Math.cos(s),o=t*Math.sin(s);return[e,r,o]};d.rgb.ansi16=function(n,e=null){let[t,i,s]=n,r=e===null?d.rgb.hsv(n)[2]:e;if(r=Math.round(r/50),r===0)return 30;let o=30+(Math.round(s/255)<<2|Math.round(i/255)<<1|Math.round(t/255));return r===2&&(o+=60),o};d.hsv.ansi16=function(n){return d.rgb.ansi16(d.hsv.rgb(n),n[2])};d.rgb.ansi256=function(n){let e=n[0],t=n[1],i=n[2];return e===t&&t===i?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(t/255*5)+Math.round(i/255*5)};d.ansi16.rgb=function(n){let e=n%10;if(e===0||e===7)return n>50&&(e+=3.5),e=e/10.5*255,[e,e,e];let t=(~~(n>50)+1)*.5,i=(e&1)*t*255,s=(e>>1&1)*t*255,r=(e>>2&1)*t*255;return[i,s,r]};d.ansi256.rgb=function(n){if(n>=232){let r=(n-232)*10+8;return[r,r,r]}n-=16;let e,t=Math.floor(n/36)/5*255,i=Math.floor((e=n%36)/6)/5*255,s=e%6/5*255;return[t,i,s]};d.rgb.hex=function(n){let t=(((Math.round(n[0])&255)<<16)+((Math.round(n[1])&255)<<8)+(Math.round(n[2])&255)).toString(16).toUpperCase();return"000000".substring(t.length)+t};d.hex.rgb=function(n){let e=n.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!e)return[0,0,0];let t=e[0];e[0].length===3&&(t=t.split("").map(a=>a+a).join(""));let i=parseInt(t,16),s=i>>16&255,r=i>>8&255,o=i&255;return[s,r,o]};d.rgb.hcg=function(n){let e=n[0]/255,t=n[1]/255,i=n[2]/255,s=Math.max(Math.max(e,t),i),r=Math.min(Math.min(e,t),i),o=s-r,a,l;return o<1?a=r/(1-o):a=0,o<=0?l=0:s===e?l=(t-i)/o%6:s===t?l=2+(i-e)/o:l=4+(e-t)/o,l/=6,l%=1,[l*360,o*100,a*100]};d.hsl.hcg=function(n){let e=n[1]/100,t=n[2]/100,i=t<.5?2*e*t:2*e*(1-t),s=0;return i<1&&(s=(t-.5*i)/(1-i)),[n[0],i*100,s*100]};d.hsv.hcg=function(n){let e=n[1]/100,t=n[2]/100,i=e*t,s=0;return i<1&&(s=(t-i)/(1-i)),[n[0],i*100,s*100]};d.hcg.rgb=function(n){let e=n[0]/360,t=n[1]/100,i=n[2]/100;if(t===0)return[i*255,i*255,i*255];let s=[0,0,0],r=e%1*6,o=r%1,a=1-o,l=0;switch(Math.floor(r)){case 0:s[0]=1,s[1]=o,s[2]=0;break;case 1:s[0]=a,s[1]=1,s[2]=0;break;case 2:s[0]=0,s[1]=1,s[2]=o;break;case 3:s[0]=0,s[1]=a,s[2]=1;break;case 4:s[0]=o,s[1]=0,s[2]=1;break;default:s[0]=1,s[1]=0,s[2]=a}return l=(1-t)*i,[(t*s[0]+l)*255,(t*s[1]+l)*255,(t*s[2]+l)*255]};d.hcg.hsv=function(n){let e=n[1]/100,t=n[2]/100,i=e+t*(1-e),s=0;return i>0&&(s=e/i),[n[0],s*100,i*100]};d.hcg.hsl=function(n){let e=n[1]/100,i=n[2]/100*(1-e)+.5*e,s=0;return i>0&&i<.5?s=e/(2*i):i>=.5&&i<1&&(s=e/(2*(1-i))),[n[0],s*100,i*100]};d.hcg.hwb=function(n){let e=n[1]/100,t=n[2]/100,i=e+t*(1-e);return[n[0],(i-e)*100,(1-i)*100]};d.hwb.hcg=function(n){let e=n[1]/100,i=1-n[2]/100,s=i-e,r=0;return s<1&&(r=(i-s)/(1-s)),[n[0],s*100,r*100]};d.apple.rgb=function(n){return[n[0]/65535*255,n[1]/65535*255,n[2]/65535*255]};d.rgb.apple=function(n){return[n[0]/255*65535,n[1]/255*65535,n[2]/255*65535]};d.gray.rgb=function(n){return[n[0]/100*255,n[0]/100*255,n[0]/100*255]};d.gray.hsl=function(n){return[0,0,n[0]]};d.gray.hsv=d.gray.hsl;d.gray.hwb=function(n){return[0,100,n[0]]};d.gray.cmyk=function(n){return[0,0,0,n[0]]};d.gray.lab=function(n){return[n[0],0,0]};d.gray.hex=function(n){let e=Math.round(n[0]/100*255)&255,i=((e<<16)+(e<<8)+e).toString(16).toUpperCase();return"000000".substring(i.length)+i};d.rgb.gray=function(n){return[(n[0]+n[1]+n[2])/3/255*100]}});var lt=b((Fn,at)=>{"use strict";var Y=ke();function Li(){let n={},e=Object.keys(Y);for(let t=e.length,i=0;i<t;i++)n[e[i]]={distance:-1,parent:null};return n}function $i(n){let e=Li(),t=[n];for(e[n].distance=0;t.length;){let i=t.pop(),s=Object.keys(Y[i]);for(let r=s.length,o=0;o<r;o++){let a=s[o],l=e[a];l.distance===-1&&(l.distance=e[i].distance+1,l.parent=i,t.unshift(a))}}return e}function Mi(n,e){return function(t){return e(n(t))}}function Vi(n,e){let t=[e[n].parent,n],i=Y[e[n].parent][n],s=e[n].parent;for(;e[s].parent;)t.unshift(e[s].parent),i=Mi(Y[e[s].parent][s],i),s=e[s].parent;return i.conversion=t,i}at.exports=function(n){let e=$i(n),t={},i=Object.keys(e);for(let s=i.length,r=0;r<s;r++){let o=i[r];e[o].parent!==null&&(t[o]=Vi(o,e))}return t}});var dt=b((jn,ct)=>{"use strict";var Ce=ke(),Fi=lt(),M={},ji=Object.keys(Ce);function Hi(n){let e=function(...t){let i=t[0];return i==null?i:(i.length>1&&(t=i),n(t))};return"conversion"in n&&(e.conversion=n.conversion),e}function Bi(n){let e=function(...t){let i=t[0];if(i==null)return i;i.length>1&&(t=i);let s=n(t);if(typeof s=="object")for(let r=s.length,o=0;o<r;o++)s[o]=Math.round(s[o]);return s};return"conversion"in n&&(e.conversion=n.conversion),e}ji.forEach(n=>{M[n]={},Object.defineProperty(M[n],"channels",{value:Ce[n].channels}),Object.defineProperty(M[n],"labels",{value:Ce[n].labels});let e=Fi(n);Object.keys(e).forEach(i=>{let s=e[i];M[n][i]=Bi(s),M[n][i].raw=Hi(s)})});ct.exports=M});var gt=b((Hn,ft)=>{"use strict";var ht=(n,e)=>(...t)=>`\x1B[${n(...t)+e}m`,ut=(n,e)=>(...t)=>{let i=n(...t);return`\x1B[${38+e};5;${i}m`},pt=(n,e)=>(...t)=>{let i=n(...t);return`\x1B[${38+e};2;${i[0]};${i[1]};${i[2]}m`},Q=n=>n,mt=(n,e,t)=>[n,e,t],V=(n,e,t)=>{Object.defineProperty(n,e,{get:()=>{let i=t();return Object.defineProperty(n,e,{value:i,enumerable:!0,configurable:!0}),i},enumerable:!0,configurable:!0})},ve,F=(n,e,t,i)=>{ve===void 0&&(ve=dt());let s=i?10:0,r={};for(let[o,a]of Object.entries(ve)){let l=o==="ansi16"?"ansi":o;o===e?r[l]=n(t,s):typeof a=="object"&&(r[l]=n(a[e],s))}return r};function Gi(){let n=new Map,e={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};e.color.gray=e.color.blackBright,e.bgColor.bgGray=e.bgColor.bgBlackBright,e.color.grey=e.color.blackBright,e.bgColor.bgGrey=e.bgColor.bgBlackBright;for(let[t,i]of Object.entries(e)){for(let[s,r]of Object.entries(i))e[s]={open:`\x1B[${r[0]}m`,close:`\x1B[${r[1]}m`},i[s]=e[s],n.set(r[0],r[1]);Object.defineProperty(e,t,{value:i,enumerable:!1})}return Object.defineProperty(e,"codes",{value:n,enumerable:!1}),e.color.close="\x1B[39m",e.bgColor.close="\x1B[49m",V(e.color,"ansi",()=>F(ht,"ansi16",Q,!1)),V(e.color,"ansi256",()=>F(ut,"ansi256",Q,!1)),V(e.color,"ansi16m",()=>F(pt,"rgb",mt,!1)),V(e.bgColor,"ansi",()=>F(ht,"ansi16",Q,!0)),V(e.bgColor,"ansi256",()=>F(ut,"ansi256",Q,!0)),V(e.bgColor,"ansi16m",()=>F(pt,"rgb",mt,!0)),e}Object.defineProperty(ft,"exports",{enumerable:!0,get:Gi})});var bt=b((Bn,yt)=>{"use strict";yt.exports=(n,e=process.argv)=>{let t=n.startsWith("-")?"":n.length===1?"-":"--",i=e.indexOf(t+n),s=e.indexOf("--");return i!==-1&&(s===-1||i<s)}});var Ct=b((Gn,kt)=>{"use strict";var Wi=require("os"),wt=require("tty"),S=bt(),{env:y}=process,N;S("no-color")||S("no-colors")||S("color=false")||S("color=never")?N=0:(S("color")||S("colors")||S("color=true")||S("color=always"))&&(N=1);"FORCE_COLOR"in y&&(y.FORCE_COLOR==="true"?N=1:y.FORCE_COLOR==="false"?N=0:N=y.FORCE_COLOR.length===0?1:Math.min(parseInt(y.FORCE_COLOR,10),3));function _e(n){return n===0?!1:{level:n,hasBasic:!0,has256:n>=2,has16m:n>=3}}function Ae(n,e){if(N===0)return 0;if(S("color=16m")||S("color=full")||S("color=truecolor"))return 3;if(S("color=256"))return 2;if(n&&!e&&N===void 0)return 0;let t=N||0;if(y.TERM==="dumb")return t;if(process.platform==="win32"){let i=Wi.release().split(".");return Number(i[0])>=10&&Number(i[2])>=10586?Number(i[2])>=14931?3:2:1}if("CI"in y)return["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI","GITHUB_ACTIONS","BUILDKITE"].some(i=>i in y)||y.CI_NAME==="codeship"?1:t;if("TEAMCITY_VERSION"in y)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(y.TEAMCITY_VERSION)?1:0;if(y.COLORTERM==="truecolor")return 3;if("TERM_PROGRAM"in y){let i=parseInt((y.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(y.TERM_PROGRAM){case"iTerm.app":return i>=3?3:2;case"Apple_Terminal":return 2}}return/-256(color)?$/i.test(y.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(y.TERM)||"COLORTERM"in y?1:t}function Ji(n){let e=Ae(n,n&&n.isTTY);return _e(e)}kt.exports={supportsColor:Ji,stdout:_e(Ae(!0,wt.isatty(1))),stderr:_e(Ae(!0,wt.isatty(2)))}});var _t=b((Wn,vt)=>{"use strict";var zi=(n,e,t)=>{let i=n.indexOf(e);if(i===-1)return n;let s=e.length,r=0,o="";do o+=n.substr(r,i-r)+e+t,r=i+s,i=n.indexOf(e,r);while(i!==-1);return o+=n.substr(r),o},Yi=(n,e,t,i)=>{let s=0,r="";do{let o=n[i-1]==="\r";r+=n.substr(s,(o?i-1:i)-s)+e+(o?`\r
|
|
24
|
-
`:`
|
|
25
|
-
`)+t,s=i+1,i=n.indexOf(`
|
|
26
|
-
`,s)}while(i!==-1);return r+=n.substr(s),r};vt.exports={stringReplaceAll:zi,stringEncaseCRLFWithFirstIndex:Yi}});var It=b((Jn,xt)=>{"use strict";var Qi=/(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi,At=/(?:^|\.)(\w+)(?:\(([^)]*)\))?/g,Ki=/^(['"])((?:\\.|(?!\1)[^\\])*)\1$/,Xi=/\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi,Zi=new Map([["n",`
|
|
27
|
-
`],["r","\r"],["t"," "],["b","\b"],["f","\f"],["v","\v"],["0","\0"],["\\","\\"],["e","\x1B"],["a","\x07"]]);function St(n){let e=n[0]==="u",t=n[1]==="{";return e&&!t&&n.length===5||n[0]==="x"&&n.length===3?String.fromCharCode(parseInt(n.slice(1),16)):e&&t?String.fromCodePoint(parseInt(n.slice(2,-1),16)):Zi.get(n)||n}function en(n,e){let t=[],i=e.trim().split(/\s*,\s*/g),s;for(let r of i){let o=Number(r);if(!Number.isNaN(o))t.push(o);else if(s=r.match(Ki))t.push(s[2].replace(Xi,(a,l,c)=>l?St(l):c));else throw new Error(`Invalid Chalk template style argument: ${r} (in style '${n}')`)}return t}function tn(n){At.lastIndex=0;let e=[],t;for(;(t=At.exec(n))!==null;){let i=t[1];if(t[2]){let s=en(i,t[2]);e.push([i].concat(s))}else e.push([i])}return e}function Ot(n,e){let t={};for(let s of e)for(let r of s.styles)t[r[0]]=s.inverse?null:r.slice(1);let i=n;for(let[s,r]of Object.entries(t))if(Array.isArray(r)){if(!(s in i))throw new Error(`Unknown Chalk style: ${s}`);i=r.length>0?i[s](...r):i[s]}return i}xt.exports=(n,e)=>{let t=[],i=[],s=[];if(e.replace(Qi,(r,o,a,l,c,h)=>{if(o)s.push(St(o));else if(l){let p=s.join("");s=[],i.push(t.length===0?p:Ot(n,t)(p)),t.push({inverse:a,styles:tn(l)})}else if(c){if(t.length===0)throw new Error("Found extraneous } in Chalk template literal");i.push(Ot(n,t)(s.join(""))),s=[],t.pop()}else s.push(h)}),i.push(s.join("")),t.length>0){let r=`Chalk template literal is missing ${t.length} closing bracket${t.length===1?"":"s"} (\`}\`)`;throw new Error(r)}return i.join("")}});var Dt=b((zn,Pt)=>{"use strict";var W=gt(),{stdout:Se,stderr:xe}=Ct(),{stringReplaceAll:nn,stringEncaseCRLFWithFirstIndex:sn}=_t(),{isArray:K}=Array,qt=["ansi","ansi","ansi256","ansi16m"],j=Object.create(null),rn=(n,e={})=>{if(e.level&&!(Number.isInteger(e.level)&&e.level>=0&&e.level<=3))throw new Error("The `level` option should be an integer from 0 to 3");let t=Se?Se.level:0;n.level=e.level===void 0?t:e.level},Ie=class{constructor(e){return Tt(e)}},Tt=n=>{let e={};return rn(e,n),e.template=(...t)=>Rt(e.template,...t),Object.setPrototypeOf(e,X.prototype),Object.setPrototypeOf(e.template,e),e.template.constructor=()=>{throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.")},e.template.Instance=Ie,e.template};function X(n){return Tt(n)}for(let[n,e]of Object.entries(W))j[n]={get(){let t=Z(this,Ee(e.open,e.close,this._styler),this._isEmpty);return Object.defineProperty(this,n,{value:t}),t}};j.visible={get(){let n=Z(this,this._styler,!0);return Object.defineProperty(this,"visible",{value:n}),n}};var Nt=["rgb","hex","keyword","hsl","hsv","hwb","ansi","ansi256"];for(let n of Nt)j[n]={get(){let{level:e}=this;return function(...t){let i=Ee(W.color[qt[e]][n](...t),W.color.close,this._styler);return Z(this,i,this._isEmpty)}}};for(let n of Nt){let e="bg"+n[0].toUpperCase()+n.slice(1);j[e]={get(){let{level:t}=this;return function(...i){let s=Ee(W.bgColor[qt[t]][n](...i),W.bgColor.close,this._styler);return Z(this,s,this._isEmpty)}}}}var on=Object.defineProperties(()=>{},{...j,level:{enumerable:!0,get(){return this._generator.level},set(n){this._generator.level=n}}}),Ee=(n,e,t)=>{let i,s;return t===void 0?(i=n,s=e):(i=t.openAll+n,s=e+t.closeAll),{open:n,close:e,openAll:i,closeAll:s,parent:t}},Z=(n,e,t)=>{let i=(...s)=>K(s[0])&&K(s[0].raw)?Et(i,Rt(i,...s)):Et(i,s.length===1?""+s[0]:s.join(" "));return Object.setPrototypeOf(i,on),i._generator=n,i._styler=e,i._isEmpty=t,i},Et=(n,e)=>{if(n.level<=0||!e)return n._isEmpty?"":e;let t=n._styler;if(t===void 0)return e;let{openAll:i,closeAll:s}=t;if(e.indexOf("\x1B")!==-1)for(;t!==void 0;)e=nn(e,t.close,t.open),t=t.parent;let r=e.indexOf(`
|
|
28
|
-
`);return r!==-1&&(e=sn(e,s,i,r)),i+e+s},Oe,Rt=(n,...e)=>{let[t]=e;if(!K(t)||!K(t.raw))return e.join(" ");let i=e.slice(1),s=[t.raw[0]];for(let r=1;r<t.length;r++)s.push(String(i[r-1]).replace(/[{}\\]/g,"\\$&"),String(t.raw[r]));return Oe===void 0&&(Oe=It()),Oe(n,s.join(""))};Object.defineProperties(X.prototype,j);var ee=X();ee.supportsColor=Se;ee.stderr=X({level:xe?xe.level:0});ee.stderr.supportsColor=xe;Pt.exports=ee});var Ye=C(ze(),1),{program:Sn,createCommand:xn,createArgument:In,createOption:En,CommanderError:qn,InvalidArgumentError:Tn,InvalidOptionArgumentError:Nn,Command:u,Argument:Rn,Option:Pn,Help:Dn}=Ye.default;var Qe="decipher-qa",$=process.env.SECRET_MODE_URL||"https://api.getdecipher.com";var v=C(require("fs")),L=C(require("path")),Mt=C(require("readline"));var Ke='---\nname: decipher-qa\ndescription: >-\n Creates QA tests by exploring your frontend codebase to understand pages, components, and UI flows,\n then generates step-by-step test instructions based on what it finds in the code.\n Handles the full lifecycle: create test, link login identity, generate steps, save, and run validation.\n Also manages tests and identities (CRUD) and provides CLI reference.\n---\n\n# /decipher-qa \u2014 Decipher QA Agent\n\nRoute based on the first word(s) of `$ARGUMENTS`:\n\n- **"create-test"** or **"create test"** \u2192 Read `create-test.md` in this skill directory and follow its instructions. Pass the remaining arguments.\n- **"validate"** \u2192 Read `create-test.md` in this skill directory and jump to Phase 6 (Run Validation). The user must provide a test ID. Initialize attemptNumber=1, maxAttempts=3, failureHistory=[].\n- **"test"** \u2192 Read `test.md` in this skill directory and follow its instructions. Pass the remaining arguments after "test".\n- **"identity"** \u2192 Read `identity.md` in this skill directory and follow its instructions. Pass the remaining arguments after "identity".\n- **"steps"** \u2192 Read `steps.md` in this skill directory and follow its instructions. Pass the remaining arguments after "steps".\n- **"cli"** \u2192 Read `cli.md` in this skill directory and follow its instructions.\n- **Natural language test request** (e.g. "make a test for checkout", "test the alert flow", "create a test for login") \u2192 Treat as `create-test`. Read `create-test.md` and follow its instructions. Use the user\'s description as the test description.\n- **Empty or unrecognized** \u2192 Show available commands:\n - `/decipher-qa create-test` \u2014 Create a new test end-to-end (name, identity, steps, validation)\n - `/decipher-qa validate` \u2014 Run validation on an existing test\n - `/decipher-qa test` \u2014 Manage QA tests (create, delete, list)\n - `/decipher-qa identity` \u2014 Manage login identities (create, delete, list)\n - `/decipher-qa steps` \u2014 Generate QA test steps by exploring your codebase\n - `/decipher-qa cli` \u2014 CLI command reference and error handling guide\n\nAll data is managed via the Decipher API through CLI commands.\n\n**IMPORTANT:** Always invoke the CLI as `decipher-qa` (it should be installed locally). If the command is not found, fall back to `npx @decipher-sdk/decipher-qa` \u2014 never use `npx decipher-qa` (the npm package name is `@decipher-sdk/decipher-qa`).\n',Xe=`# Test \u2014 Manage QA Tests
|
|
29
|
-
|
|
30
|
-
**IMPORTANT:** Always invoke the CLI as \`decipher-qa\` (it should be installed locally). If the command is not found, fall back to \`npx @decipher-sdk/decipher-qa\` \u2014 never use \`npx decipher-qa\` (the npm package name is \`@decipher-sdk/decipher-qa\`).
|
|
31
|
-
|
|
32
|
-
Route based on arguments:
|
|
33
|
-
|
|
34
|
-
- **"create"** or **"new"** or **"add"** \u2192 go to [Create Test](#create-test)
|
|
35
|
-
- **"delete"** or **"remove"** \u2192 go to [Delete Test](#delete-test)
|
|
36
|
-
- **"list"** or **"search"** or empty \u2192 go to [List Tests](#list-tests)
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## Create Test
|
|
41
|
-
|
|
42
|
-
1. Ask the user for:
|
|
43
|
-
- **name** (required) \u2014 a short descriptive name for the test
|
|
44
|
-
- **description** (required) \u2014 what this test covers
|
|
45
|
-
|
|
46
|
-
2. **Identity picker** \u2014 run \`decipher-qa identity list\`, present a picker with all identity names (and their URLs) plus a **"None"** option and a **"Create new"** option. If the user picks or creates an identity, note its \`id\`.
|
|
47
|
-
|
|
48
|
-
3. **Derive the test URL:**
|
|
49
|
-
- If an identity was chosen: extract the URL origin (protocol + host) from the identity's login URL (e.g. \`https://app.example.com/login\` \u2192 \`https://app.example.com\`). Use this as the test \`url\`.
|
|
50
|
-
- If no identity: ask the user for the test URL directly.
|
|
51
|
-
|
|
52
|
-
4. Run the CLI command:
|
|
53
|
-
\`\`\`bash
|
|
54
|
-
decipher-qa test create --name "<name>" --url "<url>" --description "<description>"
|
|
55
|
-
\`\`\`
|
|
56
|
-
If an identity was selected, also run:
|
|
57
|
-
\`\`\`bash
|
|
58
|
-
decipher-qa test update --id <testId> --identity-id <identityId>
|
|
59
|
-
\`\`\`
|
|
60
|
-
|
|
61
|
-
5. Parse the JSON output and **remember** the \`id\` \u2014 you will need it later.
|
|
62
|
-
|
|
63
|
-
6. Confirm: "Created test **<name>** (\`<id>\`)
|
|
64
|
-
View on Decipher: https://app.getdecipher.com/tests/<id>"
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## Delete Test
|
|
69
|
-
|
|
70
|
-
1. Run \`decipher-qa test list\` and show a numbered list of tests.
|
|
71
|
-
2. Ask which test to delete (by number or name).
|
|
72
|
-
3. Run:
|
|
73
|
-
\`\`\`bash
|
|
74
|
-
decipher-qa test delete --id <testId>
|
|
75
|
-
\`\`\`
|
|
76
|
-
4. Confirm: "Deleted test **<name>**"
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## List Tests
|
|
81
|
-
|
|
82
|
-
Parse the rest of the arguments after the "list" keyword:
|
|
83
|
-
- If there's a search term, pass it as \`--name\`.
|
|
84
|
-
|
|
85
|
-
Run:
|
|
86
|
-
\`\`\`bash
|
|
87
|
-
decipher-qa test list --name "<search>"
|
|
88
|
-
\`\`\`
|
|
89
|
-
|
|
90
|
-
Display a formatted table from the JSON response:
|
|
91
|
-
|
|
92
|
-
| # | Name | URL | Identity ID | Steps | Tags | Updated |
|
|
93
|
-
|---|------|-----|-------------|-------|------|---------|
|
|
94
|
-
|
|
95
|
-
For the Steps column, show the step count (e.g. "5 steps") or "\u2014" if no steps.
|
|
96
|
-
|
|
97
|
-
If no tests match, say "No tests found."
|
|
98
|
-
`,Ze=`# Identity \u2014 Manage Login Identities
|
|
99
|
-
|
|
100
|
-
**IMPORTANT:** Always invoke the CLI as \`decipher-qa\` (it should be installed locally). If the command is not found, fall back to \`npx @decipher-sdk/decipher-qa\` \u2014 never use \`npx decipher-qa\` (the npm package name is \`@decipher-sdk/decipher-qa\`).
|
|
101
|
-
|
|
102
|
-
Route based on arguments:
|
|
103
|
-
|
|
104
|
-
- **"create"** or **"new"** or **"add"** \u2192 go to [Create Identity](#create-identity)
|
|
105
|
-
- **"delete"** or **"remove"** \u2192 go to [Delete Identity](#delete-identity)
|
|
106
|
-
- **"list"** or empty \u2192 go to [List Identities](#list-identities)
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## Create Identity
|
|
111
|
-
|
|
112
|
-
1. Ask the user for:
|
|
113
|
-
- **name** (required) \u2014 a descriptive label (e.g. "Admin User", "Test Customer")
|
|
114
|
-
- **url** (required) \u2014 the login page URL (e.g. \`https://app.example.com/login\`)
|
|
115
|
-
- **username** (required) \u2014 the login username or email
|
|
116
|
-
- **password** (required) \u2014 the login password
|
|
117
|
-
|
|
118
|
-
2. Run the CLI command:
|
|
119
|
-
\`\`\`bash
|
|
120
|
-
decipher-qa identity create --name "<name>" --username "<username>" --password "<password>" --url "<url>"
|
|
121
|
-
\`\`\`
|
|
122
|
-
|
|
123
|
-
3. Parse the JSON output and **remember** the \`id\`.
|
|
124
|
-
|
|
125
|
-
4. Confirm: "Created identity **<name>** (\`<id>\`)"
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## Delete Identity
|
|
130
|
-
|
|
131
|
-
1. Run \`decipher-qa identity list\` and show a numbered list.
|
|
132
|
-
2. Ask which identity to delete (by number or name).
|
|
133
|
-
3. Run:
|
|
134
|
-
\`\`\`bash
|
|
135
|
-
decipher-qa identity delete --id <identityId>
|
|
136
|
-
\`\`\`
|
|
137
|
-
4. Confirm: "Deleted identity **<name>**"
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## List Identities
|
|
142
|
-
|
|
143
|
-
Run:
|
|
144
|
-
\`\`\`bash
|
|
145
|
-
decipher-qa identity list
|
|
146
|
-
\`\`\`
|
|
147
|
-
|
|
148
|
-
Display a formatted table from the JSON response:
|
|
149
|
-
|
|
150
|
-
| # | Name | URL | Username |
|
|
151
|
-
|---|------|-----|----------|
|
|
152
|
-
|
|
153
|
-
- If no identities exist, say "No identities found."
|
|
154
|
-
`,et=`# Steps \u2014 Generate QA Test Steps
|
|
155
|
-
|
|
156
|
-
**IMPORTANT:** Always invoke the CLI as \`decipher-qa\` (it should be installed locally). If the command is not found, fall back to \`npx @decipher-sdk/decipher-qa\` \u2014 never use \`npx decipher-qa\` (the npm package name is \`@decipher-sdk/decipher-qa\`).
|
|
157
|
-
|
|
158
|
-
The arguments contain the user's description of what they want to test (e.g. "login flow", "create a new project", "checkout as a guest").
|
|
159
|
-
|
|
160
|
-
If no arguments are provided, ask the user: **"What flow or feature would you like to generate test steps for?"**
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
## Generate Steps
|
|
165
|
-
|
|
166
|
-
### Phase 1 \u2014 Understand the Request
|
|
167
|
-
|
|
168
|
-
1. Parse the user's description from the arguments.
|
|
169
|
-
2. Confirm your understanding back to the user: "I'll generate test steps for: **<description>**"
|
|
170
|
-
3. **Assume the user is already logged in.** Authentication is handled separately by the identity attached to the test \u2014 never generate login/auth steps unless the user explicitly asks.
|
|
171
|
-
4. Ask any clarifying questions if the description is ambiguous:
|
|
172
|
-
- What page/URL does this flow start on?
|
|
173
|
-
5. Tell the user you'll now explore their codebase to understand the relevant pages.
|
|
174
|
-
|
|
175
|
-
### Phase 2 \u2014 Explore the Codebase
|
|
176
|
-
|
|
177
|
-
Systematically explore the codebase to understand the UI the flow will interact with:
|
|
178
|
-
|
|
179
|
-
1. **Find relevant pages/routes:**
|
|
180
|
-
- Based on the user's description, identify which pages/routes are involved
|
|
181
|
-
- Search for matching route files:
|
|
182
|
-
- \`Glob("**/app/**/page.tsx")\` and \`Glob("**/app/**/page.ts")\` (Next.js App Router)
|
|
183
|
-
- \`Glob("**/pages/**/*.tsx")\` and \`Glob("**/pages/**/*.ts")\` (Next.js Pages Router)
|
|
184
|
-
- \`Grep("router" or route definitions)\` for SPA routers (React Router, Vue Router, etc.)
|
|
185
|
-
- If the base URL is just the root (\`/\`), look for the main entry page
|
|
186
|
-
|
|
187
|
-
2. **Read the page component:**
|
|
188
|
-
- Understand the layout, rendered components, and state management
|
|
189
|
-
- Identify forms, buttons, links, navigation elements, modals, and interactive widgets
|
|
190
|
-
- Note conditional rendering (loading states, auth gates, feature flags)
|
|
191
|
-
|
|
192
|
-
3. **Trace child components:**
|
|
193
|
-
- Follow imports to read key child components
|
|
194
|
-
- Focus on: button labels, input placeholders/labels, link text, dropdown options
|
|
195
|
-
- Note any dynamic content (data from API calls, user-specific content)
|
|
196
|
-
|
|
197
|
-
4. **Check layouts and navigation:**
|
|
198
|
-
- Read layout files (\`layout.tsx\`, \`_app.tsx\`) to understand shared navigation
|
|
199
|
-
- Identify sidebar items, header nav, breadcrumbs, tabs
|
|
200
|
-
|
|
201
|
-
5. **Identify stateful behavior:**
|
|
202
|
-
Every test run starts a **fresh browser session** \u2014 there is no localStorage, no sessionStorage, no cookies, no cached state. Consider how this affects the flow:
|
|
203
|
-
- **First-time user experiences:** onboarding modals, welcome screens, feature tours, cookie consent banners \u2014 these WILL appear on a fresh session
|
|
204
|
-
- **Empty states:** if the page normally shows a list of items but this is a fresh session, the list may be empty. Steps need to account for "no data yet" UI
|
|
205
|
-
- **Default selections:** dropdowns, toggles, or filters may have different defaults than what a returning user sees
|
|
206
|
-
- **Conditional UI:** look for code that checks \`localStorage\`, \`sessionStorage\`, cookies, or feature flags \u2014 the fresh-session path is what will execute
|
|
207
|
-
- **Redirects:** some apps redirect first-time users to onboarding or setup pages
|
|
208
|
-
|
|
209
|
-
Flag any of these to the user in your summary \u2014 they may need \`conditional\` steps to handle them.
|
|
210
|
-
|
|
211
|
-
6. **Determine the navigation strategy:**
|
|
212
|
-
- **Direct URL (preferred):** If the target page has a static, deterministic route (e.g. \`/settings\`, \`/projects/new\`, \`/dashboard\`), use a single \`goto\` step with the full URL. This is simpler and more reliable.
|
|
213
|
-
- **Click-through navigation (when needed):** If the app's home/landing page is dynamic (e.g. redirects based on user state, shows different content per user, or the target page has no stable URL because it uses dynamic IDs), then you must describe the click-by-click navigation from a known page to the target. In this case, explain to the user exactly which UI elements to click through (sidebar items, nav links, tabs, etc.) to reach the target.
|
|
214
|
-
|
|
215
|
-
**Rule of thumb:** Always prefer a direct \`goto\` URL when one exists. Only fall back to click-through navigation when the page cannot be reached by URL alone.
|
|
216
|
-
|
|
217
|
-
7. **Summarize findings to the user** before proceeding. Present a clear picture of:
|
|
218
|
-
- What pages/components you found
|
|
219
|
-
- Key interactive elements (buttons, forms, navigation)
|
|
220
|
-
- Any dynamic or conditional content
|
|
221
|
-
- **Fresh session considerations** \u2014 onboarding flows, empty states, cookie banners, default selections that will appear on a clean session
|
|
222
|
-
- **How to reach the target page** (direct URL or navigation steps needed)
|
|
223
|
-
- Suggested test flows based on what you see
|
|
224
|
-
|
|
225
|
-
### Phase 3 \u2014 Dialogue with User
|
|
226
|
-
|
|
227
|
-
1. Summarize what you found: key pages, components, interactive elements, and navigation structure.
|
|
228
|
-
2. If the user's request is ambiguous or there are **multiple distinct flows**, suggest options and ask which to test. **If the flow is clear, skip straight to generating steps** \u2014 don't ask for permission to proceed.
|
|
229
|
-
3. Note any edge cases worth flagging (empty states, conditional UI, fresh-session behavior) but fold them into your step generation rather than asking about each one individually.
|
|
230
|
-
|
|
231
|
-
### Phase 4 \u2014 Generate Steps
|
|
232
|
-
|
|
233
|
-
Generate **all steps for the entire flow at once**. Do not break into sections or ask for feedback between sections.
|
|
234
|
-
|
|
235
|
-
1. Generate all steps by calling the CLI formatter for each:
|
|
236
|
-
\`\`\`bash
|
|
237
|
-
decipher-qa steps format --type <type> --description "<desc>" --data "<data>"
|
|
238
|
-
\`\`\`
|
|
239
|
-
Add \`--metadata '<json>'\` only when metadata is needed.
|
|
240
|
-
2. Collect the JSON output internally \u2014 **do not show raw JSON to the user**.
|
|
241
|
-
3. Display the **complete step list** grouped into logical sections:
|
|
242
|
-
\`\`\`
|
|
243
|
-
Steps (<N> total):
|
|
244
|
-
|
|
245
|
-
--- Navigate to page ---
|
|
246
|
-
1. [goto] https://app.example.com/settings/identities
|
|
247
|
-
|
|
248
|
-
--- Create identity ---
|
|
249
|
-
Fills in and submits the identity creation form.
|
|
250
|
-
2. [default] Click the "+" (Add) button next to the "Identities" header
|
|
251
|
-
3. [default] Click on the "Name" input field
|
|
252
|
-
4. [default] Type "Test Identity {{unique}}" into the "Name" input field
|
|
253
|
-
5. [default] Click the "Save" button
|
|
254
|
-
\`\`\`
|
|
255
|
-
4. Ask once: **"Here are all the steps. Any changes?"**
|
|
256
|
-
5. Apply corrections if requested.
|
|
257
|
-
|
|
258
|
-
**Display format:** \`<step_number>. [<type>] <description or data>\`
|
|
259
|
-
- For \`goto\`: show the URL
|
|
260
|
-
- For \`wait\`: show the duration with "ms" suffix
|
|
261
|
-
- For \`default\`: show the description (typed values are already inline in the description).
|
|
262
|
-
- For other types: show the description or data, whichever is more informative
|
|
263
|
-
|
|
264
|
-
**Section grouping rules:**
|
|
265
|
-
- Group steps by logical action/intent (navigation, form fill, verification, etc.)
|
|
266
|
-
- Each section gets a \`--- <Section Name> ---\` header
|
|
267
|
-
- Optionally add a 1-line description below the header if the section has 3+ steps
|
|
268
|
-
- The \`goto\` step is always its own section ("Navigate to page")
|
|
269
|
-
- \`wait\` steps stay with the section they belong to (e.g., wait after submit stays in the submit section)
|
|
270
|
-
- Step numbers are continuous across sections (no resetting)
|
|
271
|
-
|
|
272
|
-
---
|
|
273
|
-
|
|
274
|
-
## Step Writing Rules
|
|
275
|
-
|
|
276
|
-
These rules are **mandatory**. Every generated step must follow them.
|
|
277
|
-
|
|
278
|
-
### 1. One action per step \u2014 strictly atomic
|
|
279
|
-
Each step must be **exactly one** user interaction. Never combine multiple actions. A single step is one of:
|
|
280
|
-
- One click (on a button, link, checkbox, tab, dropdown option, etc.)
|
|
281
|
-
- One type/input action (typing text into a field)
|
|
282
|
-
- One key press (Tab, Enter, Escape, etc.)
|
|
283
|
-
- One hover
|
|
284
|
-
- One scroll
|
|
285
|
-
- One drag-and-drop
|
|
286
|
-
|
|
287
|
-
If you find yourself using "and" or "then" in a step description, split it into multiple steps.
|
|
288
|
-
- BAD: \`Click on the "Name" field and type "hello"\` \u2192 split into click step + type step
|
|
289
|
-
- BAD: \`Select "Editor" from the dropdown and click "Save"\` \u2192 split into select step + click step
|
|
290
|
-
- BAD: \`Type "hello" and press Enter\` \u2192 split into type step + key press step
|
|
291
|
-
|
|
292
|
-
### 2. Never skip intermediate steps
|
|
293
|
-
- Close a dropdown/modal before clicking elsewhere \u2192 separate step
|
|
294
|
-
- Click/focus a text field before typing \u2192 separate click step, then type step
|
|
295
|
-
- Dismiss a toast/banner before interacting with elements behind it \u2192 separate step
|
|
296
|
-
|
|
297
|
-
### 3. No short waits \u2014 and no redundant waits before assertions
|
|
298
|
-
**Do not generate \`wait\` steps under 2000ms.** Decipher handles short delays automatically. Only add a \`wait\` step when there is a genuinely long operation (e.g. a server-side save, a page navigation, a complex animation) that takes 2 seconds or more.
|
|
299
|
-
|
|
300
|
-
**Do not add \`wait\` steps before \`assert\` steps.** Assertions already include a built-in 2-second wait, so a preceding \`wait\` of 2000ms is always redundant. Only add a wait before an assertion if the preceding operation genuinely takes longer than 2 seconds \u2014 and in that case, set the wait to the total expected time (e.g. \`3000\`), not \`2000\`.
|
|
301
|
-
|
|
302
|
-
### 4. Description specificity
|
|
303
|
-
|
|
304
|
-
**Static UI elements** \u2014 reference exact text, icons, and location:
|
|
305
|
-
- GOOD: \`Click on the "+" (Add) button next to the "Identities" header in the left sidebar\`
|
|
306
|
-
- BAD: \`Click the add button\`
|
|
307
|
-
|
|
308
|
-
**Icons** \u2014 describe the icon AND the text or element it's next to:
|
|
309
|
-
- GOOD: \`Click on the "Edit" button (pencil icon) in the top-right corner of the "Identity Details" panel\`
|
|
310
|
-
- BAD: \`Click the edit icon\`
|
|
311
|
-
|
|
312
|
-
**Dynamic content** \u2014 use ordinal references instead of specific data values:
|
|
313
|
-
- GOOD: \`Click on the first item in the search results list\`
|
|
314
|
-
- BAD: \`Click on "Some Dynamic Item Name"\`
|
|
315
|
-
|
|
316
|
-
### 5. First step is always \`goto\` \u2014 prefer direct URLs
|
|
317
|
-
The first step must be a \`goto\` step. **If the target page has a stable route, go directly to it** (e.g. \`goto https://app.example.com/settings/identities\`) rather than navigating to the home page and clicking through. Only use the home page as the \`goto\` target when the destination has no stable URL (e.g. it requires a dynamic ID that must be discovered by interacting with the app).
|
|
318
|
-
|
|
319
|
-
### 6. \`default\` steps: \`data\` is ALWAYS empty, everything goes in \`description\`
|
|
320
|
-
For \`default\` type steps, the \`data\` field must **always** be an empty string \`""\`. The action \u2014 including what to click, what to type, and the exact value to type \u2014 must be fully described in the \`description\` field. Never put the value to fill into \`data\`.
|
|
321
|
-
- GOOD: \`--type default --description 'Type "hello@example.com" into the "Email" input field' --data ""\`
|
|
322
|
-
- BAD: \`--type default --description 'Fill in the email field' --data "hello@example.com"\`
|
|
323
|
-
|
|
324
|
-
### 7. Input fields: focus before type
|
|
325
|
-
Always have a click/focus step BEFORE a type step for input fields:
|
|
326
|
-
\`\`\`
|
|
327
|
-
Step N: Click on the "Email" input field
|
|
328
|
-
Step N+1: Type "user@example.com" into the "Email" input field
|
|
329
|
-
\`\`\`
|
|
330
|
-
|
|
331
|
-
### 8. Dropdowns and modals: close after selection
|
|
332
|
-
Always have a close/dismiss step AFTER making a selection in a dropdown or modal, before interacting with elements outside it.
|
|
333
|
-
|
|
334
|
-
### 9. Use \`{{unique}}\` for fields that require uniqueness
|
|
335
|
-
During codebase exploration, look for uniqueness constraints \u2014 database unique indexes, form validations that check for duplicates, unique email/username requirements, slug generation, etc. If a field must be unique (or the test would fail on a second run with duplicate data), use \`{{unique}}\` in the step description. **At runtime, \`{{unique}}\` is replaced with a unique number** (e.g. \`"My Item {{unique}}"\` becomes \`"My Item 48291"\`). Leave \`{{unique}}\` as-is in step descriptions \u2014 the test runner handles the substitution.
|
|
336
|
-
|
|
337
|
-
Examples:
|
|
338
|
-
- Email with unique constraint \u2192 \`Type "test+{{unique}}@example.com" into the "Email" input field\`
|
|
339
|
-
- Name that must be unique \u2192 \`Type "My Item {{unique}}" into the "Name" input field\`
|
|
340
|
-
- Username \u2192 \`Type "user-{{unique}}" into the "Username" input field\`
|
|
341
|
-
|
|
342
|
-
**Important: Referencing items created with \`{{unique}}\`**
|
|
343
|
-
Since the actual rendered text will contain a runtime-generated number (not the literal string \`{{unique}}\`), subsequent steps that reference items created with \`{{unique}}\` must use **descriptive or relative language** \u2014 never repeat the \`{{unique}}\` template as if it were the literal text on screen.
|
|
344
|
-
- GOOD: \`Verify the newly created workspace appears in the list\`
|
|
345
|
-
- GOOD: \`Click the "Revoke" button on the first pending invitation row\`
|
|
346
|
-
- GOOD: \`Confirm the item that was just created is visible in the table\`
|
|
347
|
-
- BAD: \`Verify "QA Workspace {{unique}}" appears in the list\` \u2014 the actual text on screen will be something like "QA Workspace 48291", not literally "QA Workspace {{unique}}"
|
|
348
|
-
- BAD: \`Click the "Revoke" button for "teammate+{{unique}}@example.com"\` \u2014 the actual email on screen will contain a number, not \`{{unique}}\`
|
|
349
|
-
|
|
350
|
-
---
|
|
351
|
-
|
|
352
|
-
## Step Type Reference
|
|
353
|
-
|
|
354
|
-
| Type | \`data\` field | \`description\` field | When to use |
|
|
355
|
-
|------|-------------|---------------------|-------------|
|
|
356
|
-
| \`goto\` | Full URL | Auto-set to the URL | Navigate to a page. Always step 1. |
|
|
357
|
-
| \`default\` | Always empty \`""\` | Human-readable action (include typed values inline) | Any UI interaction: click, type, hover, press key |
|
|
358
|
-
| \`wait\` | Duration in ms (minimum \`"2000"\`) | Empty \`""\` | Pause for long operations (saves, page loads). Never under 2000ms. |
|
|
359
|
-
| \`assert\` | What to verify (natural language) | Empty \`""\` | Verify page state \u2014 only if user explicitly requests. Has a built-in 2-second wait, so don't add a \`wait\` step before assertions unless the operation takes >2s. Optional \`metadata.waitAfterMs\`. |
|
|
360
|
-
| \`conditional\` | Action if condition is true | The condition to check | Handle dynamic states (e.g. dismiss cookie banner if visible) |
|
|
361
|
-
| \`refresh\` | (optional) | Empty \`""\` | Reload the page |
|
|
362
|
-
|
|
363
|
-
### CLI Examples
|
|
364
|
-
|
|
365
|
-
\`\`\`bash
|
|
366
|
-
# Navigate to a page
|
|
367
|
-
decipher-qa steps format --type goto --data "https://app.example.com/dashboard"
|
|
368
|
-
|
|
369
|
-
# Click a button
|
|
370
|
-
decipher-qa steps format --type default --description 'Click the "Sign In" button' --data ""
|
|
371
|
-
|
|
372
|
-
# Type into an input field (value goes in description, data is always empty)
|
|
373
|
-
decipher-qa steps format --type default --description 'Type "admin@example.com" into the "Email" input field' --data ""
|
|
374
|
-
|
|
375
|
-
# Type with {{unique}} variable (resolved at runtime)
|
|
376
|
-
decipher-qa steps format --type default --description 'Type "test+{{unique}}@company.com" into the "Email" input field' --data ""
|
|
377
|
-
|
|
378
|
-
# Press a key
|
|
379
|
-
decipher-qa steps format --type default --description 'Press Tab to move focus from the "Email" field to the "Password" field' --data ""
|
|
380
|
-
|
|
381
|
-
# Wait for a long operation (minimum 2000ms)
|
|
382
|
-
decipher-qa steps format --type wait --data "3000"
|
|
383
|
-
|
|
384
|
-
# Conditional action
|
|
385
|
-
decipher-qa steps format --type conditional --description "A cookie consent banner is visible" --data 'Click the "Accept" button on the cookie banner'
|
|
386
|
-
|
|
387
|
-
# Refresh the page
|
|
388
|
-
decipher-qa steps format --type refresh
|
|
389
|
-
\`\`\`
|
|
390
|
-
|
|
391
|
-
---
|
|
392
|
-
|
|
393
|
-
## Variables Reference
|
|
394
|
-
|
|
395
|
-
| Variable | Use Case |
|
|
396
|
-
|----------|----------|
|
|
397
|
-
| \`{{unique}}\` | **Replaced with a unique number at runtime** (e.g. \`{{unique}}\` \u2192 \`48291\`). Use in step \`description\` for fields that need uniqueness (emails, usernames, names) to avoid conflicts on repeat runs. Only use \`{{unique}}\` in the step where the value is **typed/entered**. In later steps that reference the created item, use descriptive language (e.g. "the newly created item", "the first item in the list") since the actual on-screen text will contain the runtime number, not \`{{unique}}\`. |
|
|
398
|
-
|
|
399
|
-
Leave \`{{unique}}\` as-is in step descriptions \u2014 it is resolved by the test runner, not by this skill or the CLI.
|
|
400
|
-
|
|
401
|
-
---
|
|
402
|
-
|
|
403
|
-
## Full Worked Example
|
|
404
|
-
|
|
405
|
-
Here is a complete example. The user asked: **"create a new workspace, invite a team member with the Editor role, verify the invitation, then revoke it"**
|
|
406
|
-
|
|
407
|
-
### Exploration Summary
|
|
408
|
-
|
|
409
|
-
After exploring the codebase, the following was found:
|
|
410
|
-
- The workspaces page is at \`/workspaces\`
|
|
411
|
-
- A "New Workspace" button opens a creation dialog with a name field and a "Create" button
|
|
412
|
-
- After creation, the workspace detail page loads at \`/workspaces/<id>\` with a "Members" tab
|
|
413
|
-
- The Members tab has an "Invite Member" button that opens a dialog with an email input and a role dropdown (Viewer, Editor, Admin)
|
|
414
|
-
- Pending invitations appear in a "Pending Invitations" section with a "Revoke" button per row
|
|
415
|
-
|
|
416
|
-
### Generated Steps
|
|
417
|
-
|
|
418
|
-
\`\`\`bash
|
|
419
|
-
# Step 1: Navigate to the workspaces page
|
|
420
|
-
decipher-qa steps format --type goto --data "https://app.example.com/workspaces"
|
|
421
|
-
|
|
422
|
-
# Step 2: Click the New Workspace button
|
|
423
|
-
decipher-qa steps format --type default --description 'Click the "New Workspace" button in the top-right corner of the page' --data ""
|
|
424
|
-
|
|
425
|
-
# Step 3: Click the Workspace Name input
|
|
426
|
-
decipher-qa steps format --type default --description 'Click on the "Workspace Name" input field in the creation dialog' --data ""
|
|
427
|
-
|
|
428
|
-
# Step 4: Type the workspace name
|
|
429
|
-
decipher-qa steps format --type default --description 'Type "QA Workspace {{unique}}" into the "Workspace Name" input field' --data ""
|
|
430
|
-
|
|
431
|
-
# Step 5: Click Create
|
|
432
|
-
decipher-qa steps format --type default --description 'Click the "Create" button in the creation dialog' --data ""
|
|
433
|
-
|
|
434
|
-
# Step 6: Wait for workspace creation and page navigation
|
|
435
|
-
decipher-qa steps format --type wait --data "3000"
|
|
436
|
-
|
|
437
|
-
# Step 7: Click the Members tab
|
|
438
|
-
decipher-qa steps format --type default --description 'Click the "Members" tab in the workspace detail page' --data ""
|
|
439
|
-
|
|
440
|
-
# Step 8: Click the Invite Member button
|
|
441
|
-
decipher-qa steps format --type default --description 'Click the "Invite Member" button in the Members tab' --data ""
|
|
442
|
-
|
|
443
|
-
# Step 9: Click the Email input
|
|
444
|
-
decipher-qa steps format --type default --description 'Click on the "Email" input field in the invite dialog' --data ""
|
|
445
|
-
|
|
446
|
-
# Step 10: Type the email
|
|
447
|
-
decipher-qa steps format --type default --description 'Type "teammate+{{unique}}@example.com" into the "Email" input field' --data ""
|
|
448
|
-
|
|
449
|
-
# Step 11: Click the Role dropdown
|
|
450
|
-
decipher-qa steps format --type default --description 'Click the "Role" dropdown in the invite dialog' --data ""
|
|
451
|
-
|
|
452
|
-
# Step 12: Select Editor from the dropdown
|
|
453
|
-
decipher-qa steps format --type default --description 'Select "Editor" from the role dropdown options' --data ""
|
|
454
|
-
|
|
455
|
-
# Step 13: Click Send Invite
|
|
456
|
-
decipher-qa steps format --type default --description 'Click the "Send Invite" button in the invite dialog' --data ""
|
|
457
|
-
|
|
458
|
-
# Step 14: Assert the invitation appears (assertions have a built-in 2s wait \u2014 no wait step needed)
|
|
459
|
-
decipher-qa steps format --type assert --data 'A new pending invitation with role "Editor" appears in the "Pending Invitations" section'
|
|
460
|
-
|
|
461
|
-
# Step 15: Click the Revoke button
|
|
462
|
-
decipher-qa steps format --type default --description 'Click the "Revoke" button on the most recently added pending invitation row' --data ""
|
|
463
|
-
|
|
464
|
-
# Step 16: Click Confirm in the revocation dialog
|
|
465
|
-
decipher-qa steps format --type default --description 'Click the "Confirm" button in the revocation confirmation dialog' --data ""
|
|
466
|
-
|
|
467
|
-
# Step 17: Assert the invitation is removed (no wait step needed \u2014 assertion waits automatically)
|
|
468
|
-
decipher-qa steps format --type assert --data 'The pending invitation that was just revoked is no longer visible in the "Pending Invitations" section'
|
|
469
|
-
\`\`\`
|
|
470
|
-
|
|
471
|
-
After collecting the JSON output, display the steps grouped into logical sections:
|
|
472
|
-
|
|
473
|
-
\`\`\`
|
|
474
|
-
Steps (17 total):
|
|
475
|
-
|
|
476
|
-
--- Navigate to workspaces ---
|
|
477
|
-
1. [goto] https://app.example.com/workspaces
|
|
478
|
-
|
|
479
|
-
--- Create workspace ---
|
|
480
|
-
Creates a new workspace with a unique name.
|
|
481
|
-
2. [default] Click the "New Workspace" button in the top-right corner of the page
|
|
482
|
-
3. [default] Click on the "Workspace Name" input field in the creation dialog
|
|
483
|
-
4. [default] Type "QA Workspace {{unique}}" into the "Workspace Name" input field
|
|
484
|
-
5. [default] Click the "Create" button in the creation dialog
|
|
485
|
-
6. [wait] 3000ms \u2014 workspace creation and page navigation
|
|
486
|
-
|
|
487
|
-
--- Invite team member ---
|
|
488
|
-
Invites a new team member with the Editor role.
|
|
489
|
-
7. [default] Click the "Members" tab in the workspace detail page
|
|
490
|
-
8. [default] Click the "Invite Member" button in the Members tab
|
|
491
|
-
9. [default] Click on the "Email" input field in the invite dialog
|
|
492
|
-
10. [default] Type "teammate+{{unique}}@example.com" into the "Email" input field
|
|
493
|
-
11. [default] Click the "Role" dropdown in the invite dialog
|
|
494
|
-
12. [default] Select "Editor" from the role dropdown options
|
|
495
|
-
13. [default] Click the "Send Invite" button in the invite dialog
|
|
496
|
-
|
|
497
|
-
--- Verify and revoke invitation ---
|
|
498
|
-
Confirms the invitation was created, then revokes it.
|
|
499
|
-
14. [assert] A new pending invitation with role "Editor" appears in the "Pending Invitations" section
|
|
500
|
-
15. [default] Click the "Revoke" button on the most recently added pending invitation row
|
|
501
|
-
16. [default] Click the "Confirm" button in the revocation confirmation dialog
|
|
502
|
-
17. [assert] The pending invitation that was just revoked is no longer visible in the "Pending Invitations" section
|
|
503
|
-
\`\`\`
|
|
504
|
-
`,tt='# CLI \u2014 Decipher QA Agent Command Reference\n\nThis is a reference for the `decipher-qa` CLI tool. Use it to run commands, understand errors, and know when to bring the user into the loop.\n\n**IMPORTANT:** Always invoke the CLI as `decipher-qa` (it should be installed locally). If the command is not found, fall back to `npx @decipher-sdk/decipher-qa` \u2014 never use `npx decipher-qa` (the npm package name is `@decipher-sdk/decipher-qa`).\n\n---\n\n## Commands\n\n### `decipher-qa init`\nScaffold skills into the nearest git repository.\n```bash\ndecipher-qa init # create skill files (skip existing)\ndecipher-qa init --force # overwrite existing skill files\n```\n\n### `decipher-qa screenshot`\nDownload a screenshot to `.decipher/screenshots/` in the current working directory. Returns the file path to stdout.\n```bash\ndecipher-qa screenshot --url "<screenshot_url>"\n```\nUse this to view screenshots from `test get` or `validation-progress` responses. After downloading, use the Read tool on the returned file path to view the image.\n\n### `decipher-qa login`\nAuthenticate with the Decipher API. **This is interactive \u2014 the user must run it in their terminal.**\n```bash\ndecipher-qa login\n```\n\n### `decipher-qa whoami`\nShow the currently authenticated user and organization.\n```bash\ndecipher-qa whoami\n```\n\n### `decipher-qa test`\nManage QA tests. All IDs are numeric.\n```bash\ndecipher-qa test list # list all tests (includes steps)\ndecipher-qa test list --name "<search>" # filter by name\ndecipher-qa test create --name "<n>" --url "<u>" --description "<d>" # create a test\ndecipher-qa test get --id <id> # get test with steps and screenshots\ndecipher-qa test update --id <id> --name "<n>" # update a test\ndecipher-qa test update --id <id> --identity-id <id> # link identity\ndecipher-qa test update --id <id> --tags "tag1,tag2" # set tags\ndecipher-qa test delete --id <id> # delete a test\ndecipher-qa test set-steps --id <id> --steps \'<json>\' # set steps array for a test\ndecipher-qa test run-validation --id <id> # trigger validation\ndecipher-qa test validation-progress --id <id> [--include-steps] # check validation progress\ndecipher-qa test start-run --id <id> # start a test run\ndecipher-qa test step-logs --id <id> # get step logs with IDs and selectors\ndecipher-qa test check-resumability --id <id> --steps \'<json>\' [--edited-step-ids \'id1,id2\'] # check if resume or restart needed\ndecipher-qa test resume-validation --id <id> [--steps \'<json>\'] [--edited-step-ids \'id1,id2\'] # resume paused validation with edits\n```\n\n### `decipher-qa identity`\nManage login identities. All IDs are numeric.\n```bash\ndecipher-qa identity list # list all identities\ndecipher-qa identity list --name "<search>" # filter by name\ndecipher-qa identity create --name "<n>" --username "<u>" --password "<p>" --url "<url>" # create\ndecipher-qa identity get --id <id> # get identity\ndecipher-qa identity update --id <id> --name "<n>" # update\ndecipher-qa identity delete --id <id> # delete\n```\n\n### `decipher-qa steps format`\nFormat a test step as JSON.\n```bash\ndecipher-qa steps format --type goto --data "https://app.example.com"\ndecipher-qa steps format --type default --description \'Click "Save"\' --data ""\ndecipher-qa steps format --type wait --data "3000"\ndecipher-qa steps format --type conditional --description "Banner is visible" --data \'Dismiss the banner\'\ndecipher-qa steps format --type assert --data "Page title is Dashboard"\ndecipher-qa steps format --type refresh\n```\nValid `--type` values: `goto`, `default`, `wait`, `assert`, `conditional`, `refresh`\n\n---\n\n## Error Handling\n\nWhen a CLI command fails, match the error output against this table to determine the cause and correct action.\n\n| Error pattern | Cause | Action |\n|---|---|---|\n| `Config not found` | User has never logged in | User must run `decipher-qa login` in their terminal |\n| `Token is invalid, revoked, or expired` | 401 from API \u2014 auth token expired | User must re-authenticate with `decipher-qa login` |\n| `Could not connect to Decipher API` | Network failure or API down | Ask user to check their network connection |\n| `not_found_error` | Invalid or stale ID | Use `decipher-qa test get --id <id>` or list items and retry with a valid ID |\n| `validation_error` | Invalid input data | Check the error message for which field is invalid |\n| `Invalid step type` | Wrong `--type` value passed to `steps format` | Use one of: `goto`, `default`, `wait`, `assert`, `conditional`, `refresh` |\n| `Invalid steps JSON` | Malformed JSON or non-array passed to `test set-steps --steps` | Ensure the value is a valid JSON array string |\n\n---\n\n## When to Bring the User Into the Loop\n\n**Always stop and involve the user when:**\n\n- **`login` is needed** \u2014 this command is interactive and must be run in the user\'s terminal. You cannot run it on their behalf.\n- **Token expiration or revocation** \u2014 the user must re-authenticate by running `decipher-qa login`.\n- **Network errors** \u2014 the user may need to check their connection, VPN, or firewall.\n- **Unexpected HTTP status codes** \u2014 if the API returns something other than 200 or a known error, report the status code and response to the user.\n- **Repeated failures** \u2014 if a command fails more than twice for the same reason, stop retrying, explain the issue, and ask the user for guidance.\n',it=`# Create Test \u2014 End-to-End Test Creation Workflow
|
|
505
|
-
|
|
506
|
-
**IMPORTANT:** Always invoke the CLI as \`decipher-qa\` (it should be installed locally). If the command is not found, fall back to \`npx @decipher-sdk/decipher-qa\` \u2014 never use \`npx decipher-qa\` (the npm package name is \`@decipher-sdk/decipher-qa\`).
|
|
507
|
-
|
|
508
|
-
This skill guides you through the full lifecycle of creating a QA test: gathering info, exploring the codebase to generate steps, getting user confirmation, then creating the test record, linking an identity, saving steps, running validation, and monitoring progress.
|
|
509
|
-
|
|
510
|
-
**Key principle:** Nothing is created until the user explicitly approves. Gather all info, generate steps, show a full summary, and only then create the test record. This avoids orphan records and wasted API calls.
|
|
511
|
-
|
|
512
|
-
---
|
|
513
|
-
|
|
514
|
-
## Phase 1 \u2014 Gather Info
|
|
515
|
-
|
|
516
|
-
Collect all required information from the user. Do NOT proceed until you have clear, complete answers for each field.
|
|
517
|
-
|
|
518
|
-
1. **Determine the base URL** \u2014 run \`decipher-qa identity list\` to get existing identities. Use their URLs to offer choices:
|
|
519
|
-
- **If identities exist:** Extract the unique URL origins (protocol + host) from identity login URLs. Present them as options:
|
|
520
|
-
1. \`https://app.example.com\` \u2014 Production (from identity "Admin User")
|
|
521
|
-
2. Enter a different URL
|
|
522
|
-
- **If no identities exist:** Ask the user for the base URL directly (e.g. \`https://app.example.com\`).
|
|
523
|
-
|
|
524
|
-
2. Ask the user for:
|
|
525
|
-
- **name** (required) \u2014 a short descriptive name for the test (e.g. "Checkout as guest", "Create new project")
|
|
526
|
-
- **description** (required) \u2014 what this test covers and what user actions it should simulate (e.g. "Navigate to the checkout page, add an item to the cart, fill in shipping details, and complete the purchase as a guest user")
|
|
527
|
-
|
|
528
|
-
3. If the description is vague or too broad, ask clarifying questions before proceeding:
|
|
529
|
-
- What specific flow or feature should be tested?
|
|
530
|
-
- What page does the flow start on?
|
|
531
|
-
- What is the expected end state?
|
|
532
|
-
- Are there any edge cases to handle (e.g. popups, banners, empty states)?
|
|
533
|
-
|
|
534
|
-
4. **Confirm the info** \u2014 summarize back to the user:
|
|
535
|
-
\`\`\`
|
|
536
|
-
Test info:
|
|
537
|
-
Name: <name>
|
|
538
|
-
URL: <url>
|
|
539
|
-
Description: <description>
|
|
540
|
-
\`\`\`
|
|
541
|
-
Ask: **"Does this look right?"** \u2014 wait for confirmation before proceeding.
|
|
542
|
-
|
|
543
|
-
5. **Remember** the name, url, and description. Do NOT create the test yet.
|
|
544
|
-
|
|
545
|
-
---
|
|
546
|
-
|
|
547
|
-
## Phase 2 \u2014 Generate Steps
|
|
548
|
-
|
|
549
|
-
Read \`steps.md\` in this skill directory and follow its 4-phase workflow with these overrides:
|
|
550
|
-
|
|
551
|
-
- **Base URL override:** Use the \`url\` from Phase 1 for all URLs in generated steps. Do NOT use \`localhost\` or any other URL unless it matches the user's \`url\`.
|
|
552
|
-
- **Description override:** Use the \`description\` from Phase 1 as the starting context for what to test. Skip the "What flow or feature would you like to generate test steps for?" prompt \u2014 you already know.
|
|
553
|
-
- **All other rules apply:** Follow the full codebase exploration, step writing rules, and step type reference from \`steps.md\`.
|
|
554
|
-
|
|
555
|
-
Collect all generated step JSON objects in memory as an array. Do NOT show raw JSON to the user \u2014 display the clean readable format as described in \`steps.md\`.
|
|
556
|
-
|
|
557
|
-
---
|
|
558
|
-
|
|
559
|
-
## Phase 3 \u2014 Review & Confirm Steps
|
|
560
|
-
|
|
561
|
-
**STOP here and wait for explicit user approval before proceeding.**
|
|
562
|
-
|
|
563
|
-
1. Display the full step list grouped into logical sections:
|
|
564
|
-
\`\`\`
|
|
565
|
-
Steps (<N> total):
|
|
566
|
-
|
|
567
|
-
--- Navigate to page ---
|
|
568
|
-
1. [goto] https://app.example.com/dashboard
|
|
569
|
-
|
|
570
|
-
--- Create project ---
|
|
571
|
-
2. [default] Click the "New Project" button
|
|
572
|
-
...
|
|
573
|
-
\`\`\`
|
|
574
|
-
|
|
575
|
-
2. Ask: **"Here are the steps. Any changes?"**
|
|
576
|
-
|
|
577
|
-
3. If the user requests changes:
|
|
578
|
-
- Apply corrections
|
|
579
|
-
- Re-display the updated step list
|
|
580
|
-
- Ask for confirmation again
|
|
581
|
-
|
|
582
|
-
4. **Only proceed after the user explicitly confirms the steps.**
|
|
583
|
-
|
|
584
|
-
---
|
|
585
|
-
|
|
586
|
-
## Phase 4 \u2014 Choose Identity
|
|
587
|
-
|
|
588
|
-
1. Run \`decipher-qa identity list\` to check existing identities.
|
|
589
|
-
|
|
590
|
-
2. **If identities exist:**
|
|
591
|
-
- Show a numbered list of identity names (with their URLs)
|
|
592
|
-
- Offer these choices:
|
|
593
|
-
1. Select an existing identity (by number)
|
|
594
|
-
2. **None** \u2014 skip identity linking
|
|
595
|
-
3. **Create new** \u2014 ask for name, url, username, password, then run \`decipher-qa identity create --name "<name>" --username "<username>" --password "<password>" --url "<url>"\`
|
|
596
|
-
|
|
597
|
-
3. **If no identities exist:**
|
|
598
|
-
- Ask: "No identities found. Would you like to create a login identity for this test, or skip?"
|
|
599
|
-
- If create: follow the identity creation flow
|
|
600
|
-
- If skip: continue without linking
|
|
601
|
-
|
|
602
|
-
4. **Remember** the chosen identity (if any). Do NOT create the test yet.
|
|
603
|
-
|
|
604
|
-
---
|
|
605
|
-
|
|
606
|
-
## Phase 5 \u2014 Create the Test, Link Identity & Save Steps
|
|
607
|
-
|
|
608
|
-
1. Create the test:
|
|
609
|
-
\`\`\`bash
|
|
610
|
-
decipher-qa test create --name "<name>" --url "<url>" --description "<description>"
|
|
611
|
-
\`\`\`
|
|
612
|
-
|
|
613
|
-
2. Parse the JSON output and **remember** the \`id\`, \`url\`, and \`decipherUrl\`.
|
|
614
|
-
|
|
615
|
-
3. If an identity was chosen in Phase 4, link it:
|
|
616
|
-
\`\`\`bash
|
|
617
|
-
decipher-qa test update --id <testId> --identity-id <identityId>
|
|
618
|
-
\`\`\`
|
|
619
|
-
|
|
620
|
-
4. Save the steps:
|
|
621
|
-
\`\`\`bash
|
|
622
|
-
decipher-qa test set-steps --id <testId> --steps '<json_array>'
|
|
623
|
-
\`\`\`
|
|
624
|
-
|
|
625
|
-
5. Confirm: "Created test **<name>** (\`<id>\`) with **<N>** steps.
|
|
626
|
-
View on Decipher: https://app.getdecipher.com/tests/<id>"
|
|
627
|
-
|
|
628
|
-
---
|
|
629
|
-
|
|
630
|
-
## Phase 6 \u2014 Run Validation
|
|
631
|
-
|
|
632
|
-
1. If this is the first attempt, initialize: attemptNumber=1, maxAttempts=3, failureHistory=[]
|
|
633
|
-
2. Run:
|
|
634
|
-
\`\`\`bash
|
|
635
|
-
decipher-qa test run-validation --id <testId>
|
|
636
|
-
\`\`\`
|
|
637
|
-
3. Tell the user: "Validation triggered for test \`<testId>\`. Spawning a monitor to track progress...
|
|
638
|
-
Watch live: https://app.getdecipher.com/tests/<testId>"
|
|
639
|
-
4. Proceed immediately to Phase 7.
|
|
640
|
-
|
|
641
|
-
---
|
|
642
|
-
|
|
643
|
-
## Phase 7 \u2014 Auto-Polling Validation Monitor & Iteration Loop
|
|
644
|
-
|
|
645
|
-
### Phase 7a \u2014 Spawn Validation Monitor Sub-Agent
|
|
646
|
-
|
|
647
|
-
**Permission setup:** The sub-agent needs to run Bash commands (\`decipher-qa\`, \`sleep\`). These should be pre-approved in \`.claude/settings.json\` (added by \`decipher-qa init\`). If the sub-agent's Bash commands are denied, tell the user to run \`decipher-qa init --force\` to update permissions, or manually add \`"Bash(decipher-qa:*)"\` and \`"Bash(sleep:*)"\` to \`.claude/settings.json\` under \`permissions.allow\`.
|
|
648
|
-
|
|
649
|
-
Use the **Task tool** (subagent_type: "general-purpose", model: "sonnet", run_in_background: true) to spawn a background sub-agent with the following prompt. Pass the \`testId\` into the prompt. After spawning, tell the user: "Validation monitor running in background \u2014 you can continue giving me requirements or other tasks while it runs."
|
|
650
|
-
|
|
651
|
-
\`\`\`
|
|
652
|
-
You are a background validation monitor. Your job is to poll validation progress and return a structured report.
|
|
653
|
-
|
|
654
|
-
**Polling loop:**
|
|
655
|
-
1. Run: \`decipher-qa test validation-progress --id <testId>\` (without --include-screenshots \u2014 lightweight polling)
|
|
656
|
-
2. Check the \`status\` field in the JSON response:
|
|
657
|
-
- "running" \u2192 Log progress (completedSteps/totalSteps), wait ~20 seconds, poll again
|
|
658
|
-
- "completed" \u2192 Go to **Return Success**
|
|
659
|
-
- "failed" or "paused_on_failure" \u2192 Go to **Fetch Screenshots & Analyze Failure**
|
|
660
|
-
- "paused_by_user" \u2192 Return immediately: "STATUS: PAUSED_BY_USER"
|
|
661
|
-
3. Timeout after 30 polls (~10 min) \u2192 Return: "STATUS: TIMEOUT"
|
|
662
|
-
4. If a network error occurs during polling, wait 30 seconds and retry once. If it fails again, return: "STATUS: ERROR\\nDETAILS: <error message>"
|
|
663
|
-
|
|
664
|
-
**Viewing screenshots:**
|
|
665
|
-
To view a screenshot, download it and then read it:
|
|
666
|
-
1. Run: \`decipher-qa screenshot --url "<screenshot_url>"\` \u2014 this saves the image to \`.decipher/screenshots/\` and prints the file path
|
|
667
|
-
2. Use the Read tool on the returned file path to view the image
|
|
668
|
-
|
|
669
|
-
**Return Success:**
|
|
670
|
-
- Do NOT review screenshots \u2014 just return immediately:
|
|
671
|
-
\`\`\`
|
|
672
|
-
STATUS: SUCCESS
|
|
673
|
-
STEPS_COMPLETED: <number>
|
|
674
|
-
\`\`\`
|
|
675
|
-
|
|
676
|
-
**Fetch Screenshots & Analyze Failure:**
|
|
677
|
-
- The polling response already has failure metadata (reason, step, browserState) but screenshot URLs are null.
|
|
678
|
-
- Fetch the full response with screenshots:
|
|
679
|
-
\`decipher-qa test validation-progress --id <testId> --include-steps\`
|
|
680
|
-
- Extract the \`failure\` object (stepNumber, stepDescription, failureReason, failureScreenshotUrl, browserState)
|
|
681
|
-
- Extract the \`steps\` array \u2014 each step has \`afterScreenshotUrl\` (screenshot taken after the step executed)
|
|
682
|
-
|
|
683
|
-
**Perform a 3-step structured analysis:**
|
|
684
|
-
|
|
685
|
-
**Step 1 \u2014 Assess the failed step:**
|
|
686
|
-
- View the failure screenshot (\`failure.failureScreenshotUrl\`)
|
|
687
|
-
- View the \`afterScreenshotUrl\` of the step immediately before the failed step (if it exists)
|
|
688
|
-
- Determine: Is this a GENUINE failure at this step, or did something go wrong earlier?
|
|
689
|
-
- GENUINE: The page looks correct for this step \u2014 the right page is loaded, previous steps completed \u2014 but the action itself failed (wrong selector, element not found, timing issue)
|
|
690
|
-
- EARLIER PROBLEM: The page doesn't look right for this step \u2014 wrong page, unexpected modal/popup, previous action clearly didn't complete, logged out unexpectedly
|
|
691
|
-
|
|
692
|
-
**Step 2 \u2014 If earlier problem detected, walk backwards through ALL steps:**
|
|
693
|
-
- Starting from the step before the failed step, go backwards through each step that has an \`afterScreenshotUrl\`
|
|
694
|
-
- For each step, view the \`afterScreenshotUrl\` and ask: "Does the page after this step look like what I'd expect given the step description?"
|
|
695
|
-
- Stop when you find the root cause (first step where things went wrong) or you've viewed 8 screenshots total
|
|
696
|
-
- Skip steps that don't have screenshots \u2014 move to the previous step
|
|
697
|
-
- Categorize each problematic step you find:
|
|
698
|
-
- \`improperly_executed\` \u2014 step ran but didn't achieve its goal (clicked wrong thing, typed in wrong field)
|
|
699
|
-
- \`missing_step\` \u2014 a needed action is missing between this step and the next
|
|
700
|
-
- \`wrong_page_state\` \u2014 page was in an unexpected state before this step ran
|
|
701
|
-
|
|
702
|
-
**Step 3 \u2014 Return structured report:**
|
|
703
|
-
\`\`\`
|
|
704
|
-
STATUS: FAILED
|
|
705
|
-
FAILED_AT_STEP: <number>
|
|
706
|
-
STEP_DESCRIPTION: <what the step was trying to do>
|
|
707
|
-
FAILURE_REASON: <error message from the failure object>
|
|
708
|
-
BROWSER_URL: <url from browserState>
|
|
709
|
-
PAGE_TITLE: <title from browserState>
|
|
710
|
-
FAILURE_IS_GENUINE: <true|false>
|
|
711
|
-
|
|
712
|
-
ROOT_CAUSE_ANALYSIS:
|
|
713
|
-
ROOT_CAUSE_STEP: <step number where the problem actually originated \u2014 same as FAILED_AT_STEP if genuine>
|
|
714
|
-
ROOT_CAUSE_TYPE: <genuine_failure|improperly_executed|missing_step|wrong_page_state>
|
|
715
|
-
ROOT_CAUSE_EXPLANATION: <1-2 sentence explanation of what went wrong and why>
|
|
716
|
-
|
|
717
|
-
PROBLEMATIC_STEPS:
|
|
718
|
-
STEP <N>:
|
|
719
|
-
ISSUE: <improperly_executed|needs_step_before|needs_step_after|should_be_removed>
|
|
720
|
-
CURRENT_DESCRIPTION: "<current step description>"
|
|
721
|
-
VISUAL_OBSERVATION: "<what the screenshot actually shows after this step>"
|
|
722
|
-
SUGGESTED_FIX: "<specific fix suggestion \u2014 e.g. rewrite description to X, add a step that does Y>"
|
|
723
|
-
(repeat for each problematic step found, ordered by step number)
|
|
724
|
-
|
|
725
|
-
DIAGNOSIS: <2-3 sentence summary of the overall problem and recommended fix approach>
|
|
726
|
-
|
|
727
|
-
ALL_STEPS_JSON: <full steps array as JSON for reference>
|
|
728
|
-
\`\`\`
|
|
729
|
-
|
|
730
|
-
**Edge cases:**
|
|
731
|
-
- If the failure is on step 1 (goto): There are no previous steps \u2014 mark as GENUINE failure, analyze only the failure screenshot
|
|
732
|
-
- If a step has no screenshot: Skip it during backwards walk, note it in the report
|
|
733
|
-
- If you hit the 8-screenshot budget without finding root cause: Note "Root cause may be earlier than analyzed" in DIAGNOSIS
|
|
734
|
-
\`\`\`
|
|
735
|
-
|
|
736
|
-
### Phase 7b \u2014 Handle Monitor Result
|
|
737
|
-
|
|
738
|
-
When the sub-agent returns, parse its output by STATUS:
|
|
739
|
-
|
|
740
|
-
- **SUCCESS** \u2192 Tell the user: "Validation passed! All <N> steps completed successfully." \u2192 Proceed to Phase 8.
|
|
741
|
-
- **PAUSED_BY_USER** \u2192 Tell the user: "Validation was paused by user. You can resume it from the Decipher dashboard." \u2192 Proceed to Phase 8.
|
|
742
|
-
- **TIMEOUT** \u2192 Tell the user: "Validation is still running after ~10 minutes. Check the Decipher dashboard for progress." \u2192 Proceed to Phase 8.
|
|
743
|
-
- **ERROR** \u2192 Tell the user: "Encountered an error while monitoring: <details>. Check \`decipher-qa test validation-progress --id <testId>\` manually." \u2192 Proceed to Phase 8.
|
|
744
|
-
- **FAILED** \u2192 Enter the **Iteration Loop** below.
|
|
745
|
-
|
|
746
|
-
### Iteration Loop (on failure)
|
|
747
|
-
|
|
748
|
-
**CRITICAL RULE:** You must ALWAYS call \`check-resumability\` (step 7) to determine whether to resume or restart. NEVER skip this call and go directly to \`set-steps\` + \`run-validation\` or \`resume-validation\` based on your own judgment. The API has server-side logic that you cannot replicate \u2014 always let it decide.
|
|
749
|
-
|
|
750
|
-
1. **Display the failure to the user:**
|
|
751
|
-
Show the sub-agent's root cause analysis clearly:
|
|
752
|
-
\`\`\`
|
|
753
|
-
Validation failed (attempt <attemptNumber>/<maxAttempts>):
|
|
754
|
-
Failed at step <X>: <step description>
|
|
755
|
-
Reason: <failureReason>
|
|
756
|
-
|
|
757
|
-
Root cause: Step <ROOT_CAUSE_STEP> \u2014 <ROOT_CAUSE_TYPE>
|
|
758
|
-
<ROOT_CAUSE_EXPLANATION>
|
|
759
|
-
|
|
760
|
-
Problematic steps:
|
|
761
|
-
- Step <N>: <ISSUE> \u2014 <SUGGESTED_FIX>
|
|
762
|
-
(repeat for each problematic step)
|
|
763
|
-
|
|
764
|
-
Diagnosis: <DIAGNOSIS from sub-agent>
|
|
765
|
-
\`\`\`
|
|
766
|
-
|
|
767
|
-
2. **Check if max retries reached:** If \`attemptNumber >= maxAttempts\` (3):
|
|
768
|
-
- Stop retrying
|
|
769
|
-
- Display the full failure history (all attempts, what failed, what fixes were tried)
|
|
770
|
-
- Link to the Decipher dashboard: "You can review and fix this test at <decipherUrl>"
|
|
771
|
-
- Proceed to Phase 8.
|
|
772
|
-
|
|
773
|
-
3. **Check for login failures:** If the failure reason indicates a login/authentication problem (credentials invalid, login page error, identity-related failure):
|
|
774
|
-
- Do NOT attempt to fix steps \u2014 the issue is with credentials, not step logic
|
|
775
|
-
- Tell the user: "This appears to be a login/credential issue. Please update the identity credentials and retry."
|
|
776
|
-
- Proceed to Phase 8.
|
|
777
|
-
|
|
778
|
-
4. **Get step logs for resume/restart flow** (if \`attemptNumber < maxAttempts\`):
|
|
779
|
-
\`\`\`bash
|
|
780
|
-
decipher-qa test step-logs --id <testId>
|
|
781
|
-
\`\`\`
|
|
782
|
-
This returns steps with their UUIDs (\`stepId\`), selectors, and execution metadata. **Important:** The response uses camelCase field names (\`stepId\`, \`stepNumber\`). You need this data for the resumability check later (step UUIDs, selectors for unchanged steps) \u2014 the sub-agent has already done the visual analysis.
|
|
783
|
-
|
|
784
|
-
5. **Validate sub-agent findings against the codebase, then fix steps:**
|
|
785
|
-
The sub-agent's analysis is a starting point \u2014 it tells you WHAT looks wrong visually, but it cannot see the codebase. You MUST validate its findings before making changes.
|
|
786
|
-
|
|
787
|
-
a. **Validate against codebase** \u2014 For EACH step in the sub-agent's PROBLEMATIC_STEPS:
|
|
788
|
-
- Read the relevant source files (components, pages) that the step interacts with
|
|
789
|
-
- Verify the sub-agent's SUGGESTED_FIX makes sense given the actual UI code \u2014 the sub-agent only saw screenshots, so its suggestions may reference elements that don't exist or miss the real fix
|
|
790
|
-
- Cross-check with step logs (selectors found, execution metadata) to understand what the validator actually tried
|
|
791
|
-
- If the sub-agent's suggestion conflicts with what the code shows, trust the code \u2014 override the suggestion with the correct fix
|
|
792
|
-
b. **Determine the right fix for each problematic step** based on your codebase validation:
|
|
793
|
-
- \`improperly_executed\` \u2192 Read the target component's code, find the correct element/label/text, rewrite the step description to match the actual UI (follow step-writing rules from \`steps.md\`)
|
|
794
|
-
- \`needs_step_before\` / \`needs_step_after\` \u2192 Understand the actual page flow from the code, generate a step that matches real UI elements
|
|
795
|
-
- \`should_be_removed\` \u2192 Confirm from the code that the step is truly unnecessary before removing
|
|
796
|
-
c. **Check \`failureHistory\`** \u2014 if the same root cause step failed with the same reason in a previous attempt, the previous fix was insufficient. Try a fundamentally different approach:
|
|
797
|
-
- Add a \`wait\` step before the failing step
|
|
798
|
-
- Restructure the flow (different navigation path, different UI element)
|
|
799
|
-
- Re-explore the codebase more broadly (check parent components, layout files, route definitions)
|
|
800
|
-
d. Generate fixed steps following all step-writing rules from \`steps.md\`
|
|
801
|
-
|
|
802
|
-
6. **Prepare fixed steps for resumability check:**
|
|
803
|
-
Transform the step-logs response into the format expected by \`check-resumability\`:
|
|
804
|
-
- Map \`stepId\` \u2192 \`id\` and \`stepNumber\` \u2192 \`step_number\` (camelCase \u2192 snake_case)
|
|
805
|
-
- Keep existing \`id\` values for unchanged steps (this enables resume)
|
|
806
|
-
- Each step must have: \`id\` (from step-logs), \`step_number\`, \`type\`, \`description\`, \`data\`
|
|
807
|
-
- **Do NOT include \`selectors\` for any step where \`description\` or \`data\` was changed** \u2014 the original selectors were discovered for the old text and are no longer valid. Only carry forward \`selectors\` on steps whose text is completely unchanged.
|
|
808
|
-
- Track which step IDs were edited \u2192 \`editedStepIds\` (comma-separated list of UUIDs)
|
|
809
|
-
|
|
810
|
-
7. **Check resumability \u2014 MANDATORY, NEVER SKIP:**
|
|
811
|
-
**You MUST always call \`check-resumability\` before deciding whether to resume or restart.** Never assume the answer \u2014 even if the fix seems obvious (e.g. removing steps, editing many steps, or the failure was early in the flow). The server has logic you do not have. Always let the API decide.
|
|
812
|
-
\`\`\`bash
|
|
813
|
-
decipher-qa test check-resumability --id <testId> --steps '<fixed_steps_json>' --edited-step-ids 'id1,id2'
|
|
814
|
-
\`\`\`
|
|
815
|
-
This returns an \`action\` field indicating how to proceed.
|
|
816
|
-
|
|
817
|
-
8. **Execute based on the \`action\` returned by \`check-resumability\` (never decide on your own):**
|
|
818
|
-
- **\`resume\`** \u2014 Keep the existing browser session (faster):
|
|
819
|
-
\`\`\`bash
|
|
820
|
-
decipher-qa test resume-validation --id <testId> --steps '<fixed_steps_json>' --edited-step-ids 'id1,id2'
|
|
821
|
-
\`\`\`
|
|
822
|
-
**Do NOT call \`set-steps\` before \`resume-validation\`** \u2014 \`set-steps\` assigns new UUIDs which breaks step ID tracking needed for resume.
|
|
823
|
-
- **\`restart\`** or **\`not_resumable\`** \u2014 New browser session required:
|
|
824
|
-
\`\`\`bash
|
|
825
|
-
decipher-qa test set-steps --id <testId> --steps '<steps_json>'
|
|
826
|
-
decipher-qa test run-validation --id <testId>
|
|
827
|
-
\`\`\`
|
|
828
|
-
For the restart path, strip the \`id\` field from each step before passing to \`set-steps\` (it generates new UUIDs). **To speed up the restart**, include \`selectors\` from the step-logs response for **unchanged steps** \u2014 this lets the validator use the fast cached-selector path instead of slow AI re-discovery. For **edited or new steps**, omit \`selectors\` so the AI re-discovers them. Example:
|
|
829
|
-
\`\`\`json
|
|
830
|
-
[
|
|
831
|
-
{"type":"goto","description":"","data":"https://example.com"},
|
|
832
|
-
{"type":"default","description":"Click the Save button","data":"","selectors":{"css":[".save-btn"],"playwright":["button >> text=Save"],"actionType":"click"}},
|
|
833
|
-
{"type":"default","description":"NEW or EDITED step \u2014 no selectors","data":""}
|
|
834
|
-
]
|
|
835
|
-
\`\`\`
|
|
836
|
-
- **\`complete\`** \u2014 All remaining steps already passed. Validation is done \u2014 proceed to Phase 8.
|
|
837
|
-
|
|
838
|
-
9. Record in failureHistory: \`{ attempt: <N>, failedStep: <stepNumber>, reason: <failureReason>, fixApplied: <description of what was changed>, retryAction: <resume|restart> }\`
|
|
839
|
-
10. Increment attemptNumber
|
|
840
|
-
11. Go back to **Phase 7a** \u2014 spawn a new monitor sub-agent
|
|
841
|
-
|
|
842
|
-
---
|
|
843
|
-
|
|
844
|
-
## Phase 8 \u2014 Summary & Next Steps
|
|
845
|
-
|
|
846
|
-
Display a final summary:
|
|
847
|
-
|
|
848
|
-
\`\`\`
|
|
849
|
-
Test created and validated!
|
|
850
|
-
|
|
851
|
-
Name: <name>
|
|
852
|
-
ID: <id>
|
|
853
|
-
URL: <url>
|
|
854
|
-
Decipher: <decipherUrl>
|
|
855
|
-
Identity: <identity name or "None">
|
|
856
|
-
Steps: <N> steps
|
|
857
|
-
Validation: PASSED / FAILED after N attempts / TIMEOUT / PAUSED
|
|
858
|
-
Attempts: <attemptNumber>/<maxAttempts>
|
|
859
|
-
|
|
860
|
-
Next actions:
|
|
861
|
-
decipher-qa test start-run --id <id> \u2014 Start a test run (if validation passed)
|
|
862
|
-
/decipher-qa validate <id> \u2014 Re-run validation
|
|
863
|
-
/decipher-qa create-test \u2014 Create another test end-to-end
|
|
864
|
-
\`\`\`
|
|
865
|
-
`;var R=C(Dt()),Ut=R.default.hex("#6C5CE7"),qe=R.default.dim,Lt=R.default.bold,A=n=>console.log(R.default.green(" + ")+n),P=n=>console.error(R.default.red(" x ")+n),w=n=>console.log(R.default.cyan(" * ")+n),x=n=>console.log(R.default.yellow(" ! ")+n),E=(n,e)=>console.log(qe(" "+n.padEnd(14))+Lt(e));function H(n){console.log(),console.log(" "+Ut(">>")+Lt(" Decipher QA ")+Ut("<<")+" "+qe(n)),console.log()}function Te(){console.log(qe(" "+"-".repeat(46)))}var te=C(require("fs")),$t=C(require("os")),ie=C(require("path")),_=ie.default.join($t.default.homedir(),".decipher","qa-config.json");function D(){te.default.existsSync(_)||(console.error(JSON.stringify({error:`Config not found at ${_}. Run \`decipher-qa login\` first.`})),process.exit(1));let n=te.default.readFileSync(_,"utf-8"),e=JSON.parse(n);return e.token||(console.error(JSON.stringify({error:`No token found in ${_}. Run \`decipher-qa login\` to authenticate.`})),process.exit(1)),e}function ne(n){let e=n;for(;;){if(te.default.existsSync(ie.default.join(e,".git")))return e;let t=ie.default.dirname(e);if(t===e)return null;e=t}}var an=[{relPath:".claude/skills/decipher-qa/SKILL.md",content:Ke},{relPath:".claude/skills/decipher-qa/test.md",content:Xe},{relPath:".claude/skills/decipher-qa/identity.md",content:Ze},{relPath:".claude/skills/decipher-qa/steps.md",content:et},{relPath:".claude/skills/decipher-qa/cli.md",content:tt},{relPath:".claude/skills/decipher-qa/create-test.md",content:it}],ln=["Bash(decipher-qa:*)","Bash(npx @decipher-sdk/decipher-qa:*)","Bash(sleep:*)","Read(.decipher/**)"];function cn(n){let e=L.default.join(n,".claude","settings.json"),t={};if(v.default.existsSync(e))try{t=JSON.parse(v.default.readFileSync(e,"utf-8"))}catch{x(" .claude/settings.json was malformed, re-creating it"),t={}}t.permissions||(t.permissions={}),Array.isArray(t.permissions.allow)||(t.permissions.allow=[]);let i=new Set(t.permissions.allow),s=[];for(let r of ln)i.has(r)||(t.permissions.allow.push(r),s.push(r));return s.length>0&&(v.default.mkdirSync(L.default.dirname(e),{recursive:!0}),v.default.writeFileSync(e,JSON.stringify(t,null,2)+`
|
|
866
|
-
`,"utf-8")),{added:s}}function dn(n){let e=L.default.join(n,".gitignore"),t="";if(v.default.existsSync(e)&&(t=v.default.readFileSync(e,"utf-8")),t.split(`
|
|
867
|
-
`).some(r=>r.trim()===".decipher/"||r.trim()===".decipher"))return!1;let s=t.length>0&&!t.endsWith(`
|
|
868
|
-
`)?`
|
|
869
|
-
`:"";return v.default.writeFileSync(e,t+s+`.decipher/
|
|
870
|
-
`,"utf-8"),!0}async function hn(n){H("Initialize"),w("Looking for git repository...");let e=ne(process.cwd());e||(P("No git repository found. Run this command inside a git repo."),process.exit(1)),A("Found: "+e),console.log(),w("Creating skill files...");let t=0;for(let r of an){let o=L.default.join(e,r.relPath);if(v.default.existsSync(o)&&!n.force){x(` ${r.relPath} (exists, use --force to overwrite)`),t++;continue}v.default.mkdirSync(L.default.dirname(o),{recursive:!0}),v.default.writeFileSync(o,r.content,"utf-8"),console.log(` ${r.relPath}`)}console.log(),t>0&&!n.force&&(w(`${t} file(s) skipped. Use --force to overwrite skill files.`),console.log()),w("Configuring Claude Code permissions (.claude/settings.json)..."),console.log(" Decipher QA runs background agents to monitor test validation."),console.log(" These permissions let those agents run CLI commands and read"),console.log(" screenshots without prompting you for approval each time.");let{added:i}=cn(e);if(i.length>0){console.log();for(let r of i)console.log(` + ${r}`);console.log(),A("Permissions added.")}else A("Permissions already configured.");console.log(),w("Checking .gitignore..."),console.log(" Decipher QA stores temporary screenshots in .decipher/ for"),console.log(" failure analysis. Adding it to .gitignore keeps these out of"),console.log(" your repo."),dn(e)?(console.log(),console.log(" + .decipher/"),console.log(),A("Added .decipher/ to .gitignore.")):A(".decipher/ already in .gitignore."),console.log(),w("Checking authentication...");let s=!0;if(v.default.existsSync(_))try{let r=v.default.readFileSync(_,"utf-8"),o=JSON.parse(r);if(o.token)try{(await fetch(`${$}/api/v1/whoami`,{headers:{Authorization:`Bearer ${o.token}`}})).ok?(A("Already authenticated."),s=!1):x(" Existing token is invalid or expired.")}catch{x(" Could not reach Decipher API to verify token.")}}catch{}if(s){console.log(),w("To authenticate, grab your API token from:"),console.log(" https://www.app.getdecipher.com/settings?tab=testing"),console.log();let r=Mt.default.createInterface({input:process.stdin,output:process.stdout}),o=await new Promise(a=>{r.question(" Paste your API token: ",l=>{r.close(),a(l.trim())})});if(!o)x(" No token provided. You can run `decipher-qa login` later.");else{let a=L.default.dirname(_);v.default.mkdirSync(a,{recursive:!0}),v.default.writeFileSync(_,JSON.stringify({token:o},null,2),"utf-8"),A("Token saved to "+_)}}console.log(),A("Decipher QA skills installed!"),console.log(),w("Available commands in Claude Code:"),console.log(" /decipher-qa create-test Create a new test end-to-end (name, identity, steps, validation)"),console.log(" /decipher-qa validate Run validation on an existing test"),console.log(" /decipher-qa test Manage QA tests (create, delete, list)"),console.log(" /decipher-qa identity Manage login identities (create, delete, list)"),console.log(" /decipher-qa steps Generate QA test steps by exploring your codebase"),console.log(" /decipher-qa cli CLI command reference and error handling guide"),console.log()}var Vt=new u("init").description("Scaffold Decipher QA skills into the nearest git repository").option("-f, --force","Overwrite existing skill files",!1).action(hn);var Ft=C(require("crypto"));var Ne=["goto","default","wait","assert","conditional","auth","refresh"];function un(n){let{type:e,description:t,data:i,metadata:s}=n;e==="goto"&&i&&!/^https?:\/\//i.test(i)&&x(`Data "${i}" doesn't look like a URL for a goto step`),e==="wait"&&i&&isNaN(Number(i))&&x(`Data "${i}" doesn't look numeric for a wait step`),e==="auth"&&i!=="magic_link"&&i!=="code"&&x(`Data for auth step should be "magic_link" or "code", got "${i}"`);let r={id:Ft.default.randomUUID(),type:e,description:e==="goto"&&!t?i:e==="wait"?"":t,data:i,setByUser:!0,originFrom:"agent"};if(s)try{r.metadata=JSON.parse(s)}catch{x(`Could not parse --metadata as JSON: ${s}`),r.metadata=s}console.log(JSON.stringify(r,null,2))}var pn=new u("format").description("Generate a validated JSON step object").requiredOption("--type <type>",`Step type: ${Ne.join(", ")}`).option("--description <text>","Step description","").option("--data <value>","Step data","").option("--metadata <json>","Optional JSON metadata").action(n=>{let e=n.type;Ne.includes(e)||(console.error(`Invalid step type "${e}". Must be one of: ${Ne.join(", ")}`),process.exit(1)),un({type:e,description:n.description,data:n.data,metadata:n.metadata})}),jt=new u("steps").description("QA test step utilities").addCommand(pn);async function m(n,e){let t=D(),i=e?.method??"GET",s=new URL(n,$);if(e?.query)for(let[o,a]of Object.entries(e.query))a!==void 0&&s.searchParams.set(o,a);let r;try{r=await fetch(s.toString(),{method:i,headers:{Authorization:`Bearer ${t.token}`,...e?.body!==void 0?{"Content-Type":"application/json"}:{}},body:e?.body!==void 0?JSON.stringify(e.body):void 0})}catch{console.error(JSON.stringify({error:"Could not connect to Decipher API. Check your network connection."})),process.exit(1)}if(!r.ok){let o;try{o=await r.json()}catch{o={error:{message:`HTTP ${r.status} ${r.statusText}`}}}console.error(JSON.stringify(o,null,2)),process.exit(1)}return await r.json()}var Ht=new u("create").description("Create a new test").requiredOption("--name <name>","Test name").requiredOption("--url <url>","URL the test runs against").requiredOption("--description <text>","Test description").option("--identity-id <id>","Identity ID for authentication").option("--tags <tags>","Comma-separated tags").action(async n=>{let e={name:n.name,url:n.url,description:n.description};n.identityId!==void 0&&(e.identityId=Number(n.identityId)),n.tags!==void 0&&(e.tags=n.tags.split(",").map(i=>i.trim()));let t=await m("/api/v1/tests",{method:"POST",body:e});console.log(JSON.stringify(t,null,2))});var Bt=new u("get").description("Get a test by ID").requiredOption("--id <id>","Test ID").action(async n=>{let e=await m(`/api/v1/tests/${n.id}`,{query:{include:"steps,screenshots"}});console.log(JSON.stringify(e,null,2))});var Gt=new u("update").description("Update a test by ID").requiredOption("--id <id>","Test ID").option("--name <name>","New test name").option("--url <url>","New URL").option("--identity-id <id>","New identity ID (use 'null' to clear)").option("--description <text>","New description").option("--tags <tags>","Comma-separated tags").action(async n=>{let e={};n.name!==void 0&&(e.name=n.name),n.url!==void 0&&(e.url=n.url),n.identityId!==void 0&&(e.identityId=n.identityId==="null"?null:Number(n.identityId)),n.description!==void 0&&(e.description=n.description),n.tags!==void 0&&(e.tags=n.tags.split(",").map(i=>i.trim()));let t=await m(`/api/v1/tests/${n.id}`,{method:"PATCH",body:e});console.log(JSON.stringify(t,null,2))});var Wt=new u("delete").description("Delete a test by ID").requiredOption("--id <id>","Test ID").action(async n=>{let e=await m(`/api/v1/tests/${n.id}`,{method:"DELETE"});console.log(JSON.stringify(e,null,2))});var Jt=new u("list").description("List all tests").option("--name <search>","Filter by name").action(async n=>{let e=await m("/api/v1/tests",{query:{name:n.name,include:"steps"}});console.log(JSON.stringify(e,null,2))});var zt=new u("set-steps").description("Set the steps array for a test by ID").requiredOption("--id <id>","Test ID").requiredOption("--steps <json>","Steps as a JSON array string").action(async n=>{let e;try{if(e=JSON.parse(n.steps),!Array.isArray(e))throw new Error("Steps must be a JSON array.")}catch(i){console.error(JSON.stringify({error:`Invalid steps JSON: ${i.message}`})),process.exit(1)}let t=await m(`/api/v1/tests/${n.id}/steps`,{method:"PUT",body:{steps:e}});console.log(JSON.stringify(t,null,2))});var Yt=new u("run-validation").description("Trigger a validation run for a test").requiredOption("--id <id>","Test ID").action(async n=>{let e=await m(`/api/v1/tests/${n.id}/run-validation`,{method:"POST"});console.log(JSON.stringify(e,null,2))});var Qt=new u("validation-progress").description("Check validation progress for a test").requiredOption("--id <id>","Test ID").option("--include-steps","Include steps and screenshot URLs in the response").action(async n=>{let e=await m(`/api/v1/tests/${n.id}/validation-progress`,{query:n.includeSteps?{include:"steps"}:void 0});console.log(JSON.stringify(e,null,2))});var Kt=new u("start-run").description("Start a test run").requiredOption("--id <id>","Test ID").action(async n=>{let e=await m(`/api/v1/tests/${n.id}/runs`,{method:"POST"});console.log(JSON.stringify(e,null,2))});var Xt=new u("check-resumability").description("Check if a paused validation can be resumed or must be restarted").requiredOption("--id <id>","Test ID").requiredOption("--steps <json>","Steps as a JSON array string (with step IDs)").option("--edited-step-ids <ids>","Comma-separated UUIDs of edited steps").action(async n=>{let e;try{if(e=JSON.parse(n.steps),!Array.isArray(e))throw new Error("Steps must be a JSON array.")}catch(s){console.error(JSON.stringify({error:`Invalid steps JSON: ${s.message}`})),process.exit(1)}let t=n.editedStepIds?n.editedStepIds.split(",").map(s=>s.trim()):void 0,i=await m(`/api/v1/tests/${n.id}/check-resumability`,{method:"POST",body:{steps:e,...t?{editedStepIds:t}:{}}});console.log(JSON.stringify(i,null,2))});var Zt=new u("resume-validation").description("Resume a paused validation run with optional edited steps").requiredOption("--id <id>","Test ID").option("--steps <json>","Edited steps as a JSON array string (with step IDs preserved)").option("--edited-step-ids <ids>","Comma-separated UUIDs of edited steps").action(async n=>{let e;if(n.steps)try{if(e=JSON.parse(n.steps),!Array.isArray(e))throw new Error("Steps must be a JSON array.")}catch(s){console.error(JSON.stringify({error:`Invalid steps JSON: ${s.message}`})),process.exit(1)}let t=n.editedStepIds?n.editedStepIds.split(",").map(s=>s.trim()):void 0,i=await m(`/api/v1/tests/${n.id}/resume-validation`,{method:"POST",body:{...e?{editedSteps:e}:{},...t?{editedStepIds:t}:{}}});console.log(JSON.stringify(i,null,2))});var ei=new u("step-logs").description("Get step logs with IDs, selectors, and execution metadata").requiredOption("--id <id>","Test ID").action(async n=>{let e=await m(`/api/v1/tests/${n.id}/step-logs`);console.log(JSON.stringify(e,null,2))});var ti=new u("test").description("Manage QA tests (create, get, update, delete, list, set-steps, run-validation, validation-progress, start-run, step-logs, check-resumability, resume-validation)").hook("preAction",()=>{D()}).addCommand(Ht).addCommand(Bt).addCommand(Gt).addCommand(Wt).addCommand(Jt).addCommand(zt).addCommand(Yt).addCommand(Qt).addCommand(Kt).addCommand(Xt).addCommand(Zt).addCommand(ei);var ii=new u("create").description("Create a new identity").requiredOption("--name <name>","Identity name").requiredOption("--username <username>","Login username or email").requiredOption("--password <password>","Login password").requiredOption("--url <url>","Login page URL").option("--description <text>","Identity description").action(async n=>{let e={name:n.name,username:n.username,password:n.password,url:n.url};n.description!==void 0&&(e.description=n.description);let t=await m("/api/v1/identities",{method:"POST",body:e});console.log(JSON.stringify(t,null,2))});var ni=new u("get").description("Get an identity by ID").requiredOption("--id <id>","Identity ID").action(async n=>{let e=await m(`/api/v1/identities/${n.id}`);console.log(JSON.stringify(e,null,2))});var si=new u("update").description("Update an identity by ID").requiredOption("--id <id>","Identity ID").option("--name <name>","New identity name").option("--username <username>","New username").option("--password <password>","New password").option("--url <url>","New login URL").option("--description <text>","New description").action(async n=>{let e={};n.name!==void 0&&(e.name=n.name),n.username!==void 0&&(e.username=n.username),n.password!==void 0&&(e.password=n.password),n.url!==void 0&&(e.url=n.url),n.description!==void 0&&(e.description=n.description);let t=await m(`/api/v1/identities/${n.id}`,{method:"PATCH",body:e});console.log(JSON.stringify(t,null,2))});var ri=new u("delete").description("Delete an identity by ID").requiredOption("--id <id>","Identity ID").action(async n=>{let e=await m(`/api/v1/identities/${n.id}`,{method:"DELETE"});console.log(JSON.stringify(e,null,2))});var oi=new u("list").description("List all identities").option("--name <search>","Filter by name").action(async n=>{let e=await m("/api/v1/identities",{query:{name:n.name}});console.log(JSON.stringify(e,null,2))});var ai=new u("identity").description("Manage login identities (create, get, update, delete, list)").hook("preAction",()=>{D()}).addCommand(ii).addCommand(ni).addCommand(si).addCommand(ri).addCommand(oi);var Re=C(require("fs")),li=C(require("path")),ci=C(require("readline"));var mn="https://www.app.getdecipher.com/settings?tab=testing";async function fn(){H("Login"),w("To authenticate, grab your API token from:"),console.log(` ${mn}`),console.log();let n=ci.default.createInterface({input:process.stdin,output:process.stdout}),e=await new Promise(i=>{n.question(" Paste your API token: ",s=>{n.close(),i(s.trim())})});e||(P("No token provided. Aborting."),process.exit(1));let t=li.default.dirname(_);Re.default.mkdirSync(t,{recursive:!0}),Re.default.writeFileSync(_,JSON.stringify({token:e},null,2),"utf-8"),console.log(),A("Token saved to "+_),w("You can now use `decipher-qa test`, `decipher-qa steps`, etc."),console.log()}var di=new u("login").description("Authenticate with Decipher by saving your API token").action(fn);async function gn(){H("Who Am I");let n=D();w("Verifying token..."),console.log();let e;try{e=await fetch(`${$}/api/v1/whoami`,{headers:{Authorization:`Bearer ${n.token}`}})}catch{P("Could not connect to Decipher API."),w("Check your network connection and try again."),process.exit(1)}e.ok||(e.status===401?(P("Token is invalid, revoked, or expired."),w("Run `decipher-qa login` to re-authenticate.")):P(`Unexpected response: ${e.status} ${e.statusText}`),process.exit(1));let t=await e.json();A("Token is valid!"),console.log(),Te(),E("Key Name",t.key_name),E("Key Prefix",t.key_prefix),E("Organization",t.organization??"\u2014"),E("Scopes",t.scopes.join(", ")||"none"),E("Created By",t.created_by??"\u2014"),E("Created At",t.created_at),E("Expires At",t.expires_at??"never"),E("Last Used",t.last_used_at??"\u2014"),Te(),console.log()}var hi=new u("whoami").description("Display information about the current API token").action(gn);var Pe=C(require("fs")),De=C(require("path")),ui=C(require("crypto"));var pi=new u("screenshot").description("Download a Decipher screenshot to a temp file for viewing").requiredOption("--url <url>","The screenshot URL from decipher-qa CLI responses").action(async n=>{let e=n.url;try{let t=new URL(e);t.searchParams.set("format","raw");let i=await fetch(t.toString());i.ok||(console.error(JSON.stringify({error:`Failed to fetch screenshot: HTTP ${i.status} ${i.statusText}`})),process.exit(1));let s=i.headers.get("content-type")||"image/png",r=s.includes("webp")?".webp":s.includes("jpeg")||s.includes("jpg")?".jpg":".png",o=ui.default.createHash("md5").update(e).digest("hex").slice(0,8),a=ne(process.cwd())||process.cwd(),l=De.default.join(a,".decipher","screenshots");Pe.default.mkdirSync(l,{recursive:!0});let c=De.default.join(l,`decipher-screenshot-${o}${r}`),h=Buffer.from(await i.arrayBuffer());Pe.default.writeFileSync(c,h),console.log(c)}catch(t){let i=t instanceof Error?t.message:String(t);console.error(JSON.stringify({error:`Error fetching screenshot: ${i}`})),process.exit(1)}});var mi={name:"@decipher-sdk/decipher-qa",version:"0.0.5",bin:{"decipher-qa":"dist/index.js"},main:"./dist/index.js",files:["dist"],scripts:{build:"tsup","check-types":"tsc -p tsconfig.json --noEmit",clean:"rm -rf dist tsconfig.tsbuildinfo",dev:"tsup --watch"},author:"Decipher AI",license:"UNLICENSED",description:"Decipher QA Agent CLI \u2014 scaffolds Claude Code skills for QA test management",engines:{node:">=18"},dependencies:{chalk:"^4.1.2",commander:"^12.1.0"},devDependencies:{"@types/node":"^22.0.0",tsup:"^8.0.0",typescript:"^5.4.3"},keywords:[]};var q=new u;q.name(Qe).description("Decipher QA Agent CLI").version(mi.version,"-v, --version");q.addCommand(Vt);q.addCommand(jt);q.addCommand(ti);q.addCommand(ai);q.addCommand(di);q.addCommand(hi);q.addCommand(pi);q.parse();
|