@kitschpatrol/repo-config 8.13.1 → 8.14.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/bin/cli.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import"cosmiconfig";import"cosmiconfig-typescript-loader";import{execa as e}from"execa";import t from"fs-extra";import n from"node:fs";import{availableParallelism as r}from"node:os";import i from"node:path";import{PassThrough as a,Transform as o}from"node:stream";import{packageUp as s,packageUpSync as c}from"package-up";import l from"yargs";import{hideBin as u}from"yargs/helpers";import d from"picocolors";import{stripVTControlCharacters as f}from"node:util";import p from"@pinojs/json-colorizer";import m from"decircular";import h from"deepmerge";import g from"json-stringify-pretty-compact";import{findWorkspaces as _,findWorkspacesRoot as v}from"find-workspaces";import y from"node:fs/promises";import{globby as b}from"globby";import x,{gt as S,minVersion as ee}from"semver";import{readWantedLockfile as te}from"@pnpm/lockfile.fs";var ne=`8.13.1`;const C=[`json`,`machine`,`native`],re=C;function w(e){return typeof e==`string`&&C.includes(e)}function T(){let e=process.env.KSC_FORMAT;return w(e)?e:`native`}function ie(){let{argv:e}=process;for(let[t,n]of e.entries()){let r;n===`--format`?r=e[t+1]:n.startsWith(`--format=`)&&(r=n.slice(9)),w(r)&&(process.env.KSC_FORMAT=r)}}function ae(){let{env:e}=process;return e.NO_COLOR!==void 0&&e.NO_COLOR!==``?!1:e.FORCE_COLOR===void 0?e.TERM!==`dumb`&&void 0:e.FORCE_COLOR!==`0`&&e.FORCE_COLOR!==`false`}function E(e,{ciColor:t=!0}={}){return ae()??(e.isTTY===!0||t&&!!process.env.CI)}function D(){return T()===`json`?process.stderr:process.stdout}function O(){return T()===`machine`?d.createColors(!1):d.createColors(E(D()))}function k(e){if(!e)return{FORCE_COLOR:`0`,NO_COLOR:`1`};let t=process.env.FORCE_COLOR;return t===void 0||t===``?{FORCE_COLOR:`1`}:{}}function oe(e,t){let n=i.isAbsolute(e)?e:i.resolve(t,e),r=i.relative(process.cwd(),n);return r===``?`.`:r}const se=/\s*\n\s*/gv,ce=/\r?\n/v;function le(e){let t=e.message.replaceAll(se,` `),n=e.rule===void 0?e.tool:`${e.tool}/${e.rule}`;return e.file===void 0?`${e.severity}: ${t} [${n}]`:`${e.file}:${e.line??1}:${e.column??1}: ${e.severity}: ${t} [${n}]`}function ue(e,t){let n=(e.file??`￿`).localeCompare(t.file??`￿`);if(n!==0)return n;let r=(e.line??0)-(t.line??0);return r===0?(e.column??0)-(t.column??0):r}function de(e,t){let n=t.toSorted(ue);return{cwd:process.cwd(),diagnostics:n,success:e.every(e=>e.exitCode===0),summary:{errors:n.filter(e=>e.severity===`error`).length,infos:n.filter(e=>e.severity===`info`).length,warnings:n.filter(e=>e.severity===`warning`).length},tools:e,version:1}}function A(e){return f(e).split(ce).map(e=>e.trimEnd()).filter(e=>e.trim().length>0)}function fe(e){return e instanceof Error&&`exitCode`in e&&typeof e.exitCode==`number`}function j(e){return E(process.stdout,{ciColor:!1})?me(e):pe(e)}function pe(e){return g(m(e),{indent:2,replacer(e,t){return typeof t==`function`?t.name:t}})}function me(e){return p(pe(e),{colors:{BRACKET:`gray`}})}const he=(e,t,n)=>{let r=[...e];for(let[i,a]of t.entries())r[i]===void 0?r[i]=n.cloneUnlessOtherwiseSpecified(a,n):n.isMergeableObject(a)?r[i]=M(e[i],a,n):e.includes(a)||r.push(a);return r};function M(e,t,n={arrayMerge:he}){return h(e,t,n)}function N(e){let{tasks:t}=e;return Array.isArray(t)?t:[]}function ge(e,t){let n=[...N(e)];for(let e of N(t)){let t=n.findIndex(t=>t.label!==void 0&&t.label===e.label);t===-1?n.push(e):n[t]=e}return{...e,...t,tasks:n}}function _e(e,t){return e.startsWith(t+i.sep)}function P(){let e=F(),t=/* @__PURE__ */ new Set([e]),n=_();if(n!==null)for(let r of n){let n=i.resolve(r.location);_e(n,e)&&t.add(n)}return[...t]}function F(){let e=c();if(e===void 0)throw Error(`No package.json found.`);return i.dirname(e)}function I(){let e=v();return e===null?F():i.resolve(e.location)}function ve(e){if(e===`workspace-root`)return I();if(e===`package-dir`)return F();if(typeof e==`string`){if(!t.pathExistsSync(e))throw Error(`Custom cwd directory does not exist: ${e}`);return e}return process.cwd()}async function ye(e,t){try{let{default:n}=await import(`prettier`),r=await n.resolveConfig(e),i=await n.format(t,{filepath:e,...r});await y.writeFile(e,i,`utf8`)}catch{console.warn(`Skipped formatting ${e} since Prettier is not installed.`)}}async function L(e){try{await ye(e,await y.readFile(e,`utf8`))}catch{}}const be=/\r?\n/v;function xe(e){let t=``,n=t=>t.filter(t=>{let n=f(t);return n.trim()!==``&&!e(n)}).map(e=>`${e}\n`).join(``);return new o({flush(e){e(void 0,n([t]))},transform(e,r,i){let a=(t+e.toString()).split(be);t=a.pop()??``,i(void 0,n(a))}})}function R(e,t){let n=T()===`native`?e:void 0,r=n===void 0||n===``?``:t===void 0?n:O()[t](n),i=``,a=e=>e.filter(e=>e.trim().length>0).map(e=>r===``?`${e}\n`:`${r} ${e}\n`).join(``);return new o({flush(e){e(void 0,a([i]))},transform(e,t,n){let r=(i+e.toString()).split(be);i=r.pop()??``,n(void 0,a(r))}})}async function Se(e){let t=[];return new Promise((n,r)=>{e.on(`data`,e=>{t.push(e)}),e.on(`error`,e=>{r(e)}),e.on(`end`,()=>{n(Buffer.concat(t).toString(`utf8`))})})}function z(e,t){return t===1?e:e+`s`}async function B(e){return typeof e==`function`?e():e}async function Ce(e,t,n,r,i){let a;if(r.logPrefix===void 0)a=e;else{let t=R(r.logPrefix,r.logColor);t.pipe(e),a=t}i&&a.write(O().bold(`Running: "${r.name}() with Positional arguments: ${String(t)} and Option flags: ${String(n)}"`)+`
3
- `);try{return await r.execute(a,t,n)}catch(e){return console.error(String(e)),1}}function V(e,t,n,r,a){return[...e.subcommands??[],...e.receiveOptionFlags?n:[],...r??[],...a&&e.cache!==void 0?[...e.cache.flags,`--cache-location`,i.join(I(),`node_modules`,`.cache`,`ksc`,e.cache.name)]:[],...e.receivePositionalArguments?t:[],...e.positionalArguments??[]]}async function we(t,n,r,i,o,s){let c=1,l;if(i.logPrefix===void 0)l=t;else{let e=R(i.logPrefix,i.logColor);e.pipe(t),l=e}let u=V(i,n,r,i.optionFlags,o),d=ve(i.cwdOverride);s&&l.write(`Running: "${i.name} ${u.join(` `)}"\n`);let f=i.prettyJsonOutput?new a:void 0,p=f??l,m=k(T()===`native`&&i.prettyJsonOutput!==!0&&E(D()));try{let t=e(i.name,u,{cwd:d,env:m,preferLocal:!0,reject:!1,stdin:`inherit`});if(i.outputFilter){let e=xe(i.outputFilter),n=xe(i.outputFilter);t.stdout.pipe(e).pipe(p,{end:!1}),t.stderr.pipe(n).pipe(p,{end:!1})}else t.stdout.pipe(p,{end:!1}),t.stderr.pipe(p,{end:!1});let n=await t;if(f!==void 0){f.end();let e=await Se(f),t=j(JSON.parse(e)).split(`
4
- `);for(let e of t)l.write(`${e}\n`)}c=n.exitCode??1}catch(e){console.error(`${i.name} failed with error:`),console.error(e),fe(e)&&(c=typeof e.exitCode==`number`?e.exitCode:1)}return c}function H(e){return`execute`in e}function U(e){return`kind`in e}async function W(t,n,r,i,a){let o=V(r,t,n,r.collect?.optionFlags??r.optionFlags,i),s=ve(r.cwdOverride);try{let t=e(r.name,o,{cwd:s,env:k(!1),preferLocal:!0,reject:!1,stdin:`inherit`});a!==void 0&&t.stderr.pipe(a,{end:!1});let n=await t;return{cwd:s,exitCode:n.exitCode??1,stderr:n.stderr,stdout:n.stdout}}catch(e){return console.error(`${r.name} failed with error:`),console.error(e),{cwd:s,exitCode:fe(e)&&typeof e.exitCode==`number`?e.exitCode:1,stderr:``,stdout:``}}}function Te(e){return typeof e==`object`&&!!e&&`version`in e&&e.version===1&&`diagnostics`in e&&Array.isArray(e.diagnostics)&&`success`in e&&typeof e.success==`boolean`&&`tools`in e&&Array.isArray(e.tools)}function G(e,t){return e===0&&t.some(({severity:e})=>e===`error`)?1:e}async function Ee(e,t,n,r,i){let o=Date.now(),s=()=>Date.now()-o;if(H(r)){if(r.collect!==void 0)try{let e=await r.collect(t,n),i=G(e.exitCode,e.diagnostics);return{diagnostics:e.diagnostics,exitCode:i,tools:[{durationMs:s(),exitCode:i,name:r.name,unparsed:e.unparsed}]}}catch(e){return{diagnostics:[],exitCode:1,tools:[{durationMs:s(),exitCode:1,name:r.name,unparsed:[String(e)]}]}}let e=``,i=new a;i.on(`data`,t=>{e+=t.toString()});let o;try{o=await r.execute(i,t,n)}catch(t){e+=`\n${String(t)}`,o=1}return{diagnostics:[],exitCode:o,tools:[{durationMs:s(),exitCode:o,name:r.name,unparsed:A(e)}]}}if(U(r))throw Error(`Command groups must be expanded before collection`);if(r.outputFormatAware){let a=await W(t,n,r,i,e);try{let e=JSON.parse(a.stdout);if(!Te(e))throw Error(`Child output is not a lint report`);return{diagnostics:e.diagnostics,exitCode:a.exitCode===0&&e.success&&e.diagnostics.every(({severity:e})=>e!==`error`)?0:1,tools:e.tools}}catch{return{diagnostics:[],exitCode:a.exitCode,tools:[{durationMs:s(),exitCode:a.exitCode,name:r.name,unparsed:A(a.stdout)}]}}}let c=await W(t,n,r,i);if(r.collect!==void 0)try{let{diagnostics:e,unparsed:t}=r.collect.parse(c),n=G(c.exitCode,e);return{diagnostics:e,exitCode:n,tools:[{durationMs:s(),exitCode:n,name:r.name,unparsed:t}]}}catch(e){return{diagnostics:[],exitCode:c.exitCode,tools:[{durationMs:s(),exitCode:c.exitCode,name:r.name,unparsed:[...A(c.stdout),...A(c.stderr),String(e)]}]}}return{diagnostics:[],exitCode:c.exitCode,tools:[{durationMs:s(),exitCode:c.exitCode,name:r.name,unparsed:[...A(c.stdout),...A(c.stderr)]}]}}const De=/^ksc-/v;function K(e){return e.replace(De,``)}function q(e){return e===void 0||e.length===0?[]:e.flatMap(e=>e.split(`,`)).map(e=>K(e.trim()))}function J(e){return e.option(`skip`,{array:!0,describe:`Tool names to skip (with or without "ksc-" prefix).`,type:`string`})}function Oe(e){return e.option(`format`,{choices:re,default:`native`,describe:`Output format: "native" streams each tool's own output, "machine" prints one parseable line per issue for editor problem matchers, "json" prints an aggregate report.`})}function ke(e){return e.option(`cache`,{boolean:!0,default:!0,describe:`Use tool-native caches stored below node_modules/.cache/ksc at the workspace root. Disable with --no-cache.`})}function Ae(e,t){return t===`native`||t===`machine`&&!H(e)&&!U(e)&&e.outputFormatAware===!0}function je(e,t){for(let n of t.diagnostics)e.write(`${le(n)}\n`);for(let n of t.tools)for(let t of n.unparsed)e.write(`${t}\n`)}function Me(){return Math.min(4,r())}var Ne=class{concurrency;active=0;queue=[];constructor(e){this.concurrency=e}async run(e){this.active>=this.concurrency&&await new Promise(e=>{this.queue.push(e)}),this.active+=1;try{return await e()}finally{--this.active,this.queue.shift()?.()}}};async function Pe(e){let n=e.cache??!1,r=e.concurrency??Me();if(!Number.isInteger(r)||r<1)throw Error(`Concurrency must be a positive integer.`);return n&&await t.ensureDir(i.join(I(),`node_modules`,`.cache`,`ksc`)),{cache:n,scheduler:new Ne(r)}}const Fe=/[*?\[\]\{\}]/v;function Y(e,t){return t===void 0?e:e.filter(e=>Fe.test(e)||n.statSync(e,{throwIfNoEntry:!1})?.isDirectory()===!0||t.includes(i.extname(e).slice(1).toLowerCase()))}function Ie(e,t){return e.length===0||Y(e,t).length>0}function Le(e,t){return e.positionalArgumentMode===`none`?[]:t.length>0?Y(t,e.positionalArgumentExtensions):e.positionalArgumentDefault===void 0?[]:[e.positionalArgumentDefault]}function Re(e,t){if(t.logPrefix===void 0)return e;let n=R(t.logPrefix,t.logColor);return n.pipe(e),n}function ze(e){return U(e)?`${e.name} ${e.subcommand}`:!H(e)&&e.subcommands!==void 0?[e.name,...e.subcommands].join(` `):e.name}async function Be(e,t){if(U(e)){let n=Re(t.logStream,e);try{let r=await B(e.commands);if(t.nativeVerbose){let n=[e.subcommand,...t.positionalArguments].join(` `),i=e.showResolvedCommands?` (${r.map(e=>ze(e)).join(`, `)})`:``;t.logStream.write(`Running: "${e.name} ${n}"${i}\n`)}let i=await Ve(r,{...t,logStream:n,nativeVerbose:e.verbose,positionalArguments:Le(e,t.positionalArguments)},e.parallel===!0);return{diagnostics:i.flatMap(({diagnostics:e})=>e),exitCode:+!i.every(({exitCode:e})=>e===0),machineOutcomes:i.flatMap(({machineOutcomes:e})=>e),name:e.name,tools:i.flatMap(({tools:e})=>e)}}catch(r){let i=String(r),a={durationMs:0,exitCode:1,name:e.name,unparsed:[i]};return t.format===`native`&&n.write(`${i}\n`),{diagnostics:[],exitCode:1,machineOutcomes:[{diagnostics:[],exitCode:1,tools:[a]}],name:e.name,tools:[a]}}}return t.scheduler.run(async()=>{if(Ae(e,t.format))return{diagnostics:[],exitCode:await(H(e)?Ce(t.logStream,t.positionalArguments,t.optionFlags,e,t.nativeVerbose):we(t.logStream,t.positionalArguments,t.optionFlags,e,t.cache,t.nativeVerbose)),machineOutcomes:[],name:e.name,tools:[]};let n=await Ee(t.logStream,t.positionalArguments,t.optionFlags,e,t.cache);return{diagnostics:n.diagnostics,exitCode:n.exitCode,machineOutcomes:[n],name:e.name,tools:n.tools}})}async function Ve(e,t,n){if(!n||t.scheduler.concurrency===1){let n=[];for(let r of e)n.push(await Be(r,t));return n}await Promise.resolve();let r=/* @__PURE__ */ new Map;for(let[t,n]of e.entries()){let e=n.stage??0,i=r.get(e)??[];i.push({command:n,index:t}),r.set(e,i)}let i=Array.from({length:e.length}),a=r.keys().toArray().toSorted((e,t)=>e-t);for(let e of a){let n=r.get(e)??[],a=await Promise.all(n.map(async({command:e,index:n})=>({index:n,outcome:await Be(e,t)})));for(let{index:e,outcome:t}of a)i[e]=t}return i.filter(e=>e!==void 0)}function He(e,t,n,r,i){let a=[],o=[],s=Ie(r,i);for(let e of t){let t=!U(e)||Ie(r,e.positionalArgumentExtensions);!s||!t||n.includes(K(e.name))?o.push(e):a.push(e)}if(n.length>0){let r=new Set(o.map(e=>K(e.name))),i=n.filter(e=>!r.has(e));if(i.length>0){let n=t.map(e=>K(e.name)).join(`, `);e.write(`⚠️ ${O().yellow(`Unrecognized --skip ${z(`value`,i.length)}: ${i.join(`, `)}. Available: ${n}`)}\n`)}}return{commandsToRun:a,skippedCommands:o}}async function X(e,t,n,r,i,a,o,s=`native`){let c=typeof s==`string`?{}:s,l=typeof s==`string`?s:c.format??`native`,{commandsToRun:u,skippedCommands:d}=He(e,r,o??[],t,c.positionalArgumentExtensions),f=l===`native`&&i,{cache:p,scheduler:m}=await Pe(c),h=await Ve(u,{cache:p,format:l,logStream:e,nativeVerbose:f,optionFlags:n,positionalArguments:Y(t,c.positionalArgumentExtensions),scheduler:m},c.parallel===!0),g=h.map(({exitCode:e,name:t})=>({exitCode:e,name:t})),_=h.flatMap(({tools:e})=>e),v=h.flatMap(({diagnostics:e})=>e);if(l===`machine`)for(let t of h)for(let n of t.machineOutcomes)je(e,n);let y=r.length,b=O();if(l===`native`&&d.length>0){let t=d.map(({name:e})=>e),n=b.bold(`${t.length} / ${y} ${z(`Command`,t.length)} Skipped:`);e.write(`⏭️ ${b.dim(n)} ${b.dim(t.join(`, `))}\n`)}if(l===`native`&&a){let t=g.filter(({exitCode:e})=>e===0).map(({name:e})=>e),n=g.filter(({exitCode:e})=>e!==0).map(({name:e})=>e);if(t.length>0){let n=b.bold(`${t.length} / ${y} ${z(`Command`,t.length)} Succeeded:`);e.write(`✅ ${b.green(n)} ${b.green(t.join(`, `))}\n`)}if(n.length>0){let t=b.bold(`${n.length} / ${y} ${z(`Command`,n.length)} Failed:`);e.write(`❌ ${b.red(t)} ${b.red(n.join(`, `))}\n`)}}return{exitCode:+!g.every(({exitCode:e})=>e===0),report:l===`json`?de(_,v):void 0}}async function Ue(e){let t=await s({cwd:e});return t===void 0?void 0:i.join(i.dirname(t),`init`)}async function We(e,r,a,o){let c=await s();if(c===void 0)throw Error("The `init` command must be used in a directory with a package.json file");let l=await Ue(import.meta.dirname);if(l===void 0)return e.write(`Error: Could not locate the package containing this CLI.
5
- `),1;let u=i.dirname(c),d=(r===`file`||r===`package`)&&a!==void 0&&o!==void 0;try{if(d){let n=Object.keys(o)[0],i=t.readJsonSync(c);if(r===`package`){e.write(`Merging: \nPackage config key "${n}" → "${u}" (Because --location is set to "package")\n`);let r=M(i,o);t.writeJSONSync(c,r,{spaces:` `}),await L(c)}else n!==void 0&&Object.keys(i).includes(n)&&(e.write(`Deleting: \nPackage config key "${n}" in "${u}" (Because --location is set to "file")\n`),delete i[n],t.writeJSONSync(c,i,{spaces:` `}),await L(c))}if(!await t.pathExists(l))return 0;if((await t.readdir(l)).length===0)return e.write(`Source directory "${l}" is empty.\n`),0;e.write(`Adding initial configuration files from:\n"${l}" → "${u}"\n`),await t.copy(l,u,{async filter(o,s){let c=n.statSync(o).isFile(),l=n.existsSync(s);if(c){if(d&&r===`package`&&o.includes(a))return l?(e.write(`Deleting: \n"${o}" → "${s}" (Because --location is set to "package")\n`),t.removeSync(s)):e.write(`Skipping: \n"${o}" → "${s}" (Because --location is set to "package")\n`),!1;if(l&&(s.includes(`.vscode/`)||s.includes(`package.json`))&&i.extname(s)===`.json`){e.write(`Merging: \n"${o}" → "${s}"\n`);let n=t.readJSONSync(o),r=t.readJSONSync(s),i=s.endsWith(`.vscode/tasks.json`)?ge(r,n):M(r,n);return t.writeJSONSync(s,i,{spaces:` `}),await L(s),!1}return l?(e.write(`Overwriting: \n"${o}" → "${s}"\n`),await L(s),!0):(e.write(`Copying: \n"${o}" → "${s}"\n`),await L(s),!0)}return!0},overwrite:!0})}catch(e){return console.error(String(e)),1}return 0}async function Ge(e){let{commands:{fix:t,init:n,lint:r,printConfig:i},description:a,logColor:o,logPrefix:s,name:c,showSummary:d,verbose:f}=e;ie();let p=R(s,o);p.pipe(D());let m=l(u(process.argv)).scriptName(c).usage(`$0 <command>`,a);n!==void 0&&m.command({builder(e){let t=n.locationOptionFlag?e.option(`location`,{choices:[`file`,`package`],default:`file`,describe:`Where to store the configuration.`,type:`string`}):e;return d?J(t):t},command:`init`,describe:n.description??`Initialize by copying starter config files to your project root${n.locationOptionFlag?` or to your package.json file.`:`.`}`,async handler(e){let t=n.locationOptionFlag?e.location:void 0,r=q(e.skip),{exitCode:i}=await X(p,[],t===void 0?[]:[`--location`,t],[{async execute(e,t,r){return We(e,r.at(1),n.configFile,n.configPackageJson)},name:`copyAndMergeInitFiles`},...n.commands??[]],void 0,void 0,r);process.exitCode=i}}),r!==void 0&&m.command({builder(e){let t=ke(Oe(r.positionalArgumentMode===`none`?e:e.positional(`files`,{array:!0,...r.positionalArgumentDefault!==void 0&&{default:r.positionalArgumentDefault},describe:`Files or glob pattern to lint.`,type:`string`})));return d?J(t):t},command:r.positionalArgumentMode===`none`?`lint`:r.positionalArgumentMode===`optional`?`lint [files..]`:`lint <files..>`,describe:r.description,async handler(e){let t=e.files??[],n=q(e.skip),i=T(),{exitCode:a,report:o}=await X(p,t,[],await B(r.commands),f,d,n,{cache:e.cache,format:i,parallel:r.parallel,positionalArgumentExtensions:r.positionalArgumentExtensions});o!==void 0&&process.stdout.write(`${j(o)}\n`),process.exitCode=a}}),t!==void 0&&m.command({builder(e){let n=ke(Oe(t.positionalArgumentMode===`none`?e:e.positional(`files`,{array:!0,...t.positionalArgumentDefault!==void 0&&{default:t.positionalArgumentDefault},describe:`Files or glob pattern to fix.`,type:`string`})));return d?J(n):n},command:t.positionalArgumentMode===`none`?`fix`:t.positionalArgumentMode===`optional`?`fix [files..]`:`fix <files..>`,describe:t.description,async handler(e){let n=e.files??[],r=q(e.skip),i=T(),{exitCode:a,report:o}=await X(p,n,[],await B(t.commands),void 0,void 0,r,{cache:e.cache,format:i,parallel:t.parallel,positionalArgumentExtensions:t.positionalArgumentExtensions});o!==void 0&&process.stdout.write(`${j(o)}\n`),process.exitCode=a}}),i!==void 0&&m.command({builder(e){let t=i.positionalArgumentMode===`none`?e:e.positional(`file`,{...i.positionalArgumentDefault!==void 0&&{default:i.positionalArgumentDefault},describe:`File or glob pattern to print configuration for.`,type:`string`});return d?J(t):t},command:i.positionalArgumentMode===`none`?`print-config`:i.positionalArgumentMode===`optional`?`print-config [file]`:`print-config <file>`,describe:i.description,async handler(e){let t=e.file??void 0,n=t===void 0?[]:[t],r=q(e.skip),{exitCode:a}=await X(p,n,[],await B(i.commands),f,d,r);process.exitCode=a}}),m.alias(`h`,`help`),m.version(ne),m.alias(`v`,`version`),m.help(),m.wrap(process.stdout.isTTY?Math.min(120,m.terminalWidth()):0),await m.parseAsync()}const Z={fileRun:`Matches files below the current working directory by default.`,monorepoRun:`In a monorepo, it will also run in all packages below the current working directory.`,monorepoSearch:`Searches up to the root of a monorepo if necessary.`,multiArgumentCaveat:`Will use file arguments / globs where possible if provided, but some of the invoked tools only operate at the package scope.`,multiOptionCaveat:`Will use option flags where possible if provided, but some of the invoked tools will ignore them.`,optionalFileRun:`Package-scoped by default, file-scoped if a file argument is provided.`,packageRun:`Package-scoped.`,packageSearch:`Package-scoped.`},Ke=[/Version 2\.0,?\s*January 2004/gv,/Version 1,?\s*February 1989/gv,/Version 2,?\s*June 1991/gv,/Version 3,?\s*29 June 2007/gv,/Version 2\.1,?\s*February 1999/gv,/Version 3,?\s*19 November 2007/gv,/Version 1\.0\s*-\s*August 17th,?\s*2003/gv,/Version 1\.1,?\s*March 2000/gv,/Version 1\.2,?\s*November 2002/gv,/Version 1\.3,?\s*3 November 2008/gv,/Version 1\.0\s*-\s*22 November 2005/gv,/Version 1\.1\s*-\s*26 February 2007/gv,/Version 2,?\s*December 2004/gv,/20 December 1996/gv,/December 20,?\s*1996/gv,/11 March 1996/gv,/28 March 2007/gv,/November 1,?\s*2008/gv,/August 1,?\s*2009/gv,/1 April 19\d{2}/gv,/Copyright \(c\) 2000-2006,?\s*The Perl Foundation/giv,/Copyright \(C\) (?:\d{4},?\s*)+Free Software Foundation/gv],qe=[`node_modules/**`,`test/**`];function Je(e){let t=e;for(let e of Ke)e.lastIndex=0,t=t.replace(e,e=>e.replaceAll(/\d/gv,`X`));return t}const Ye=/(\d{4})\s*-\s*(\d{4})/v,Xe=/(\d{4})/v;function Ze(e,t){let n=Je(e),r=Ye,i=r.exec(n);if(i){let[,n,a]=i;if(Number(a)!==t){let a=`${n}-${t}`;return e.slice(0,i.index)+e.slice(i.index).replace(r,()=>a)}return e}let a=Xe,o=a.exec(n);if(o){let[,n]=o;if(Number(n)!==t){let r=`${n}-${t}`;return e.slice(0,o.index)+e.slice(o.index).replace(a,()=>r)}return e}return e}async function Qe(e){let t=(/* @__PURE__ */ new Date()).getFullYear(),n=[`**/license.txt`,`**/license`,...qe.map(e=>`!${e}`)],r=await b(n,{caseSensitiveMatch:!1,cwd:F(),followSymbolicLinks:!1,gitignore:!0}),i=[];for(let n of r)try{let r=await y.readFile(n,`utf8`),a=Ze(r,t);a!==r&&(i.push(n),e&&await y.writeFile(n,a,`utf8`))}catch(e){console.error(`Failed to process ${n}:`,e)}return i}async function $e(e,t=!1){let n=await Qe(t);if(n.length>0){e.write(`${t?`Fixed`:`Found`} ${n.length} license ${z(`file`,n.length)} with outdated copyright year:\n`);for(let t of n)e.write(` - ${t}\n`);return+!t}return 0}async function et(e){return $e(e,!1)}async function tt(){let e=await Qe(!1);return{diagnostics:e.map(e=>({file:oe(e,F()),message:`License file has an outdated copyright year`,severity:`error`,tool:`copyright-year`})),exitCode:+(e.length>0),unparsed:[]}}async function nt(e){return $e(e,!0)}const Q=`pnpm-lock.yaml`;function rt(e){let n=I(),r=i.resolve(e);for(;;){if(t.existsSync(i.join(r,Q)))return r;if(r===n)break;let e=i.dirname(r);if(e===r)break;r=e}}function it(e,t,n){let r=`${e}@${t}`;return Object.hasOwn(n,r)?r:Object.hasOwn(n,t)?t:void 0}function at(e,t){return e===void 0||e===``?t===void 0||t===``?void 0:t:t===void 0||t===``||S(e,t)?e:t}async function ot(e){let t=rt(e);if(t===void 0||t===``)throw Error(`${Q} not found at or above "${e}".`);let n=i.join(t,Q),r=await te(t,{ignoreIncompatible:!1});if(!r?.importers)throw Error(`Lockfile at "${n}" is unreadable or missing importers.`);let a=r.packages??{},o,s,c={},l={};function u(e,t){let n,r=/* @__PURE__ */ new Set;function i(e,t){if(t.startsWith(`link:`))return;let o=it(e,t,a);if(o===void 0||o===``||r.has(o))return;r.add(o);let s=a[o];if(s===void 0)return;let c=s.engines?.node;if(c!==void 0&&c!==``){let e=ee(c)?.version;e!==void 0&&e!==``&&(n===void 0||n===``||S(e,n))&&(n=e)}if(s.dependencies)for(let[e,t]of Object.entries(s.dependencies))i(e,t)}return i(e,t),n}function d(e,t){for(let[n,r]of Object.entries(e)){let e=u(n,typeof r==`string`?r:r.version);if(e===void 0||e===``)continue;let i=t?l:c;i[e]??=/* @__PURE__ */ new Set,i[e].add(n);let a=t?s:o;(a===void 0||a===``||S(e,a))&&(t?s=e:o=e)}}let f=i.relative(t,e),p=f===``?`.`:f,m=r.importers[p];m!==void 0&&(m.dependencies&&d(m.dependencies,!1),m.devDependencies&&d(m.devDependencies,!0));let h=at(o,s),g=h===void 0?void 0:`>=${h}`;return{dependencies:o!==void 0&&o!==``?{topLevelCauses:[...c[o]??[]],version:`>=${o}`}:void 0,devDependencies:s!==void 0&&s!==``?{topLevelCauses:[...l[s]??[]],version:`>=${s}`}:void 0,lockfile:n,version:g}}function st(e){let t=e.devEngines;if(t?.runtime)return(Array.isArray(t.runtime)?t.runtime:[t.runtime]).find(e=>e.name===`node`)?.version}function ct(e,t){let n=e.devEngines??{};if(n.runtime){if(Array.isArray(n.runtime)){let e=n.runtime.find(e=>e.name===`node`);e===void 0?n.runtime.push({name:`node`,version:t}):e.version=t}else n.runtime.name===`node`?n.runtime.version=t:n.runtime=[n.runtime,{name:`node`,version:t}]}else n.runtime={name:`node`,version:t};e.devEngines=n}function lt(e){let t=e.devEngines;if(t?.runtime){if(Array.isArray(t.runtime)){t.runtime=t.runtime.filter(e=>e.name!==`node`);let[e]=t.runtime;e===void 0?delete t.runtime:t.runtime.length===1&&(t.runtime=e)}else t.runtime.name===`node`&&delete t.runtime;Object.keys(t).length===0&&delete e.devEngines}}function $(e){return e.length===0?``:` (from ${e.join(`, `)})`}async function ut(e,n){let r=i.join(n,`package.json`);if(!t.existsSync(r))return{issues:[],packageJsonPath:r};let a=t.readJsonSync(r),o=a.engines?.node,s=st(a),c=await ot(n),l=c.dependencies?.version,u=c.dependencies?.topLevelCauses??[],d=c.version,f=c.devDependencies?.topLevelCauses??[],p=[];if(l!==void 0){if(o===void 0){if(p.push(`Missing engines.node — suggest setting to "${l}"${$(u)}`),e){let e=a.engines??{};e.node=l,a.engines=e}}else{let t=x.minVersion(o),n=x.minVersion(l);t&&n&&x.lt(t,n)&&(p.push(`engines.node is "${o}" but production dependencies require at least "${l}"${$(u)}`),e&&(a.engines.node=l))}}let m=(()=>{if(l!==void 0&&l!==``&&o!==void 0&&o!==``){let e=x.minVersion(l),t=x.minVersion(o);if(e&&t)return x.gt(e,t)?l:o}return l??o})(),h=m!==void 0&&m!==``?x.minVersion(m):void 0,g=d!==void 0&&d!==``?x.minVersion(d):void 0,_=g&&h&&x.gt(g,h);if(d!==void 0&&_){if(s===void 0)p.push(`devDependencies require a higher Node.js minimum (${d}) than engines.node (${m??`none`}) — suggest adding devEngines.runtime for node with version "${d}"${$(f)}`),e&&ct(a,d);else{let t=x.minVersion(s);t&&x.lt(t,g)&&(p.push(`devEngines.runtime.version for node is "${s}" but all dependencies require at least "${d}"${$(f)}`),e&&ct(a,d))}}else if(s!==void 0){let t=x.minVersion(s);t&&h&&x.lte(t,h)&&(p.push(`devEngines.runtime.version for node is redundant (engines.node already covers the requirement) — suggest removing`),e&&lt(a))}return e&&p.length>0&&(t.writeJsonSync(r,a,{spaces:` `}),await L(r)),{issues:p,packageJsonPath:r}}async function dt(e,t){let n=P(),r=0;for(let i of n){let{issues:n,packageJsonPath:a}=await ut(t,i);if(n.length!==0){e.write(`${t?`Fixed`:`Found`} ${n.length} Node.js version ${z(`issue`,n.length)} in ${a}:\n`);for(let t of n)e.write(` - ${t}\n`);t||(r=1)}}return r}async function ft(){let e=P(),t=[];for(let n of e){let{issues:e,packageJsonPath:r}=await ut(!1,n);for(let n of e)t.push({file:oe(r,process.cwd()),message:n,severity:`error`,tool:`node-version`})}return{diagnostics:t,exitCode:+(t.length>0),unparsed:[]}}async function pt(e){let t=j(await ot(F())).split(`
6
- `);for(let n of t)e.write(`${n}\n`);return 0}async function mt(e){return dt(e,!1)}async function ht(e){return dt(e,!0)}await Ge({commands:{fix:{commands:[{execute:nt,name:`copyright-year`},{execute:ht,name:`node-version`}],description:`Fix common issues like outdated copyright years in license files. ${Z.packageRun} ${Z.monorepoRun}`,positionalArgumentMode:`none`},init:{locationOptionFlag:!1},lint:{commands:[{collect:tt,execute:et,name:`copyright-year`},{collect:ft,execute:mt,name:`node-version`}],description:`Check the repo for common issues. ${Z.packageRun} ${Z.monorepoRun}`,positionalArgumentMode:`none`},printConfig:{commands:[{execute:pt,name:`node-version`}],description:`Print minimum Node.js version constraints from the pnpm lockfile.`,positionalArgumentMode:`none`}},description:`Kitschpatrol's repository-related shared configuration tools.`,logColor:`gray`,logPrefix:`[Repo Config]`,name:`ksc-repo`,order:1});export{};
2
+ import"cosmiconfig";import"cosmiconfig-typescript-loader";import{execa as e}from"execa";import t from"fs-extra";import n from"node:fs";import{availableParallelism as r}from"node:os";import i from"node:path";import{PassThrough as a,Transform as o}from"node:stream";import{packageUp as s,packageUpSync as c}from"package-up";import l from"yargs";import{hideBin as u}from"yargs/helpers";import d from"picocolors";import{stripVTControlCharacters as f}from"node:util";import p from"@pinojs/json-colorizer";import m from"decircular";import h from"deepmerge";import g from"json-stringify-pretty-compact";import{findWorkspaces as _,findWorkspacesRoot as ee}from"find-workspaces";import v from"node:fs/promises";import{globby as y}from"globby";import b,{gt as x,minVersion as te}from"semver";import{readWantedLockfile as ne}from"@pnpm/lockfile.fs";var re=`8.14.0`;const S=[`json`,`machine`,`native`],ie=S;function ae(e){return typeof e==`string`&&S.includes(e)}function C(){let e=process.env.KSC_FORMAT;return ae(e)?e:`native`}function oe(){let{argv:e}=process;for(let[t,n]of e.entries()){let r;n===`--format`?r=e[t+1]:n.startsWith(`--format=`)&&(r=n.slice(9)),ae(r)&&(process.env.KSC_FORMAT=r)}}function se(){let{env:e}=process;return e.NO_COLOR!==void 0&&e.NO_COLOR!==``?!1:e.FORCE_COLOR===void 0?e.TERM!==`dumb`&&void 0:e.FORCE_COLOR!==`0`&&e.FORCE_COLOR!==`false`}function w(e,{ciColor:t=!0}={}){return se()??(e.isTTY===!0||t&&!!process.env.CI)}function T(){return C()===`json`?process.stderr:process.stdout}function E(){return d.createColors(C()!==`machine`&&w(T()))}function ce(e){if(!e)return{FORCE_COLOR:`0`,NO_COLOR:`1`};let t=process.env.FORCE_COLOR;return t===void 0||t===``?{FORCE_COLOR:`1`}:{}}function D(e,t){let n=i.isAbsolute(e)?e:i.resolve(t,e),r=i.relative(process.cwd(),n);return r===``?`.`:r}const le=/\s*\n\s*/gv,ue=/\r?\n/v;function de(e){let t=e.message.replaceAll(le,` `),n=e.rule===void 0?e.tool:`${e.tool}/${e.rule}`;return e.file===void 0?`${e.severity}: ${t} [${n}]`:`${e.file}:${e.line??1}:${e.column??1}: ${e.severity}: ${t} [${n}]`}function fe(e,t){let n=(e.file??`￿`).localeCompare(t.file??`￿`);if(n!==0)return n;let r=(e.line??0)-(t.line??0);return r===0?(e.column??0)-(t.column??0):r}function pe(e,t){let n=t.toSorted(fe);return{cwd:process.cwd(),diagnostics:n,success:e.every(e=>e.exitCode===0),summary:{errors:n.filter(e=>e.severity===`error`).length,infos:n.filter(e=>e.severity===`info`).length,warnings:n.filter(e=>e.severity===`warning`).length},tools:e,version:1}}function O(e){return f(e).split(ue).map(e=>e.trimEnd()).filter(e=>e.trim().length>0)}function me(e){return e instanceof Error&&`exitCode`in e&&typeof e.exitCode==`number`}function k(e){return w(process.stdout,{ciColor:!1})?he(e):A(e)}function A(e){return g(m(e),{indent:2,replacer(e,t){return typeof t==`function`?t.name:t}})}function he(e){return p(A(e),{colors:{BRACKET:`gray`}})}const ge=(e,t,n)=>{let r=[...e];for(let[i,a]of t.entries())r[i]===void 0?r[i]=n.cloneUnlessOtherwiseSpecified(a,n):n.isMergeableObject(a)?r[i]=j(e[i],a,n):e.includes(a)||r.push(a);return r};function j(e,t,n={arrayMerge:ge}){return h(e,t,n)}function M(e){let{tasks:t}=e;return Array.isArray(t)?t:[]}function _e(e,t){let n=[...M(e)];for(let e of M(t)){let t=n.findIndex(t=>t.label!==void 0&&t.label===e.label);t===-1?n.push(e):n[t]=e}return{...e,...t,tasks:n}}function ve(e,t){return e.startsWith(t+i.sep)}function ye(){let e=N(),t=/* @__PURE__ */ new Set([e]),n=_();if(n!==null)for(let r of n){let n=i.resolve(r.location);ve(n,e)&&t.add(n)}return[...t]}function N(){let e=c();if(e===void 0)throw Error(`No package.json found.`);return i.dirname(e)}function P(){let e=ee();return e===null?N():i.resolve(e.location)}function F(e){if(e===`workspace-root`)return P();if(e===`package-dir`)return N();if(typeof e==`string`){if(!t.pathExistsSync(e))throw Error(`Custom cwd directory does not exist: ${e}`);return e}return process.cwd()}async function be(e,t){try{let{default:n}=await import(`prettier`),r=await n.resolveConfig(e),i=await n.format(t,{filepath:e,...r});await v.writeFile(e,i,`utf8`)}catch{console.warn(`Skipped formatting ${e} since Prettier is not installed.`)}}async function I(e){try{await be(e,await v.readFile(e,`utf8`))}catch{}}const L=/\r?\n/v;function xe(e){let t=``,n=t=>t.filter(t=>{let n=f(t);return n.trim()!==``&&!e(n)}).map(e=>`${e}\n`).join(``);return new o({flush(e){e(void 0,n([t]))},transform(e,r,i){let a=(t+e.toString()).split(L);t=a.pop()??``,i(void 0,n(a))}})}function R(e,t){let n=C()===`native`?e:void 0,r=n===void 0||n===``?``:t===void 0?n:E()[t](n),i=``,a=e=>e.filter(e=>e.trim().length>0).map(e=>r===``?`${e}\n`:`${r} ${e}\n`).join(``);return new o({flush(e){e(void 0,a([i]))},transform(e,t,n){let r=(i+e.toString()).split(L);i=r.pop()??``,n(void 0,a(r))}})}async function Se(e){let t=[];return new Promise((n,r)=>{e.on(`data`,e=>{t.push(e)}),e.on(`error`,e=>{r(e)}),e.on(`end`,()=>{n(Buffer.concat(t).toString(`utf8`))})})}function z(e,t){return t===1?e:e+`s`}async function B(e){return typeof e==`function`?e():e}async function Ce(e,t,n,r,i){let a;if(r.logPrefix===void 0)a=e;else{let t=R(r.logPrefix,r.logColor);t.pipe(e),a=t}i&&a.write(E().bold(`Running: "${r.name}() with Positional arguments: ${String(t)} and Option flags: ${String(n)}"`)+`
3
+ `);try{return await r.execute(a,t,n)}catch(e){return console.error(String(e)),1}}function we(e,t,n,r,a){return[...e.subcommands??[],...e.receiveOptionFlags?n:[],...r??[],...a&&e.cache!==void 0?[...e.cache.flags,`--cache-location`,i.join(P(),`node_modules`,`.cache`,`ksc`,e.cache.name)]:[],...e.receivePositionalArguments?t:[],...e.positionalArguments??[]]}async function Te(t,n,r,i,o,s){let c=1,l;if(i.logPrefix===void 0)l=t;else{let e=R(i.logPrefix,i.logColor);e.pipe(t),l=e}let u=we(i,n,r,i.optionFlags,o),d=F(i.cwdOverride);s&&l.write(`Running: "${i.name} ${u.join(` `)}"\n`);let f=i.prettyJsonOutput?new a:void 0,p=f??l,m=ce(C()===`native`&&i.prettyJsonOutput!==!0&&w(T()));try{let t=e(i.name,u,{cwd:d,env:m,preferLocal:!0,reject:!1,stdin:`inherit`});if(i.outputFilter){let e=xe(i.outputFilter),n=xe(i.outputFilter);t.stdout.pipe(e).pipe(p,{end:!1}),t.stderr.pipe(n).pipe(p,{end:!1})}else t.stdout.pipe(p,{end:!1}),t.stderr.pipe(p,{end:!1});let n=await t;if(f!==void 0){f.end();let e=await Se(f),t=k(JSON.parse(e)).split(`
4
+ `);for(let e of t)l.write(`${e}\n`)}c=n.exitCode??1}catch(e){console.error(`${i.name} failed with error:`),console.error(e),me(e)&&(c=typeof e.exitCode==`number`?e.exitCode:1)}return c}function V(e){return`execute`in e}function H(e){return`kind`in e}async function U(t,n,r,i,a){let o=we(r,t,n,r.collect?.optionFlags??r.optionFlags,i),s=F(r.cwdOverride);try{let t=e(r.name,o,{cwd:s,env:ce(!1),preferLocal:!0,reject:!1,stdin:`inherit`});a!==void 0&&t.stderr.pipe(a,{end:!1});let n=await t;return{cwd:s,exitCode:n.exitCode??1,stderr:n.stderr,stdout:n.stdout}}catch(e){return console.error(`${r.name} failed with error:`),console.error(e),{cwd:s,exitCode:me(e)&&typeof e.exitCode==`number`?e.exitCode:1,stderr:``,stdout:``}}}function Ee(e){return typeof e==`object`&&!!e&&`version`in e&&e.version===1&&`diagnostics`in e&&Array.isArray(e.diagnostics)&&`success`in e&&typeof e.success==`boolean`&&`tools`in e&&Array.isArray(e.tools)}function W(e,t){return e===0&&t.some(({severity:e})=>e===`error`)?1:e}async function De(e,t,n,r,i){let o=Date.now(),s=()=>Date.now()-o;if(V(r)){if(r.collect!==void 0)try{let e=await r.collect(t,n),i=W(e.exitCode,e.diagnostics);return{diagnostics:e.diagnostics,exitCode:i,tools:[{durationMs:s(),exitCode:i,name:r.name,unparsed:e.unparsed}]}}catch(e){return{diagnostics:[],exitCode:1,tools:[{durationMs:s(),exitCode:1,name:r.name,unparsed:[String(e)]}]}}let e=``,i=new a;i.on(`data`,t=>{e+=t.toString()});let o;try{o=await r.execute(i,t,n)}catch(t){e+=`\n${String(t)}`,o=1}return{diagnostics:[],exitCode:o,tools:[{durationMs:s(),exitCode:o,name:r.name,unparsed:O(e)}]}}if(H(r))throw Error(`Command groups must be expanded before collection`);if(r.outputFormatAware){let a=await U(t,n,r,i,e);try{let e=JSON.parse(a.stdout);if(!Ee(e))throw Error(`Child output is not a lint report`);return{diagnostics:e.diagnostics,exitCode:a.exitCode===0&&e.success&&e.diagnostics.every(({severity:e})=>e!==`error`)?0:1,tools:e.tools}}catch{return{diagnostics:[],exitCode:a.exitCode,tools:[{durationMs:s(),exitCode:a.exitCode,name:r.name,unparsed:O(a.stdout)}]}}}let c=await U(t,n,r,i);if(r.collect!==void 0)try{let{diagnostics:e,unparsed:t}=r.collect.parse(c),n=W(c.exitCode,e);return{diagnostics:e,exitCode:n,tools:[{durationMs:s(),exitCode:n,name:r.name,unparsed:t}]}}catch(e){return{diagnostics:[],exitCode:c.exitCode,tools:[{durationMs:s(),exitCode:c.exitCode,name:r.name,unparsed:[...O(c.stdout),...O(c.stderr),String(e)]}]}}return{diagnostics:[],exitCode:c.exitCode,tools:[{durationMs:s(),exitCode:c.exitCode,name:r.name,unparsed:[...O(c.stdout),...O(c.stderr)]}]}}const Oe=/^ksc-/v;function G(e){return e.replace(Oe,``)}function K(e){return e===void 0||e.length===0?[]:e.flatMap(e=>e.split(`,`)).map(e=>G(e.trim()))}function q(e){return e.option(`skip`,{array:!0,describe:`Tool names to skip (with or without "ksc-" prefix).`,type:`string`})}function J(e){return e.option(`format`,{choices:ie,default:`native`,describe:`Output format: "native" streams each tool's own output, "machine" prints one parseable line per issue for editor problem matchers, "json" prints an aggregate report.`})}function ke(e){return e.option(`cache`,{boolean:!0,default:!0,describe:`Use tool-native caches stored below node_modules/.cache/ksc at the workspace root. Disable with --no-cache.`})}function Ae(e,t){return t===`native`||t===`machine`&&!V(e)&&!H(e)&&e.outputFormatAware===!0}function je(e,t){for(let n of t.diagnostics)e.write(`${de(n)}\n`);for(let n of t.tools)for(let t of n.unparsed)e.write(`${t}\n`)}function Me(){return Math.min(4,r())}var Ne=class{concurrency;active=0;queue=[];constructor(e){this.concurrency=e}async run(e){this.active>=this.concurrency&&await new Promise(e=>{this.queue.push(e)}),this.active+=1;try{return await e()}finally{--this.active,this.queue.shift()?.()}}};async function Pe(e){let n=e.cache??!1,r=e.concurrency??Me();if(!Number.isInteger(r)||r<1)throw Error(`Concurrency must be a positive integer.`);return n&&await t.ensureDir(i.join(P(),`node_modules`,`.cache`,`ksc`)),{cache:n,scheduler:new Ne(r)}}const Fe=/[*?\[\]\{\}]/v,Ie=/[!\(\)*+?@\[\]\{\|\}]/gv,Le=/\/+$/v;function Y(e,t){if(t===void 0)return e;let r=t.length===1?t[0]:`{${t.join(`,`)}}`;return e.flatMap(e=>n.statSync(e,{throwIfNoEntry:!1})?.isDirectory()===!0?`${e.replace(Le,``).replaceAll(Ie,String.raw`\$&`)}/**/*.${r}`:Fe.test(e)||t.includes(i.extname(e).slice(1).toLowerCase())?e:[])}function Re(e,t){return e.length===0||Y(e,t).length>0}function ze(e,t){return e.positionalArgumentMode===`none`?[]:t.length>0?Y(t,e.positionalArgumentExtensions):e.positionalArgumentDefault===void 0?[]:[e.positionalArgumentDefault]}function Be(e,t){if(t.logPrefix===void 0)return e;let n=R(t.logPrefix,t.logColor);return n.pipe(e),n}function Ve(e){return H(e)?`${e.name} ${e.subcommand}`:V(e)||e.subcommands===void 0?e.name:[e.name,...e.subcommands].join(` `)}async function He(e,t){if(H(e)){let n=Be(t.logStream,e);try{let r=await B(e.commands);if(t.nativeVerbose){let n=[e.subcommand,...t.positionalArguments].join(` `),i=e.showResolvedCommands?` (${r.map(e=>Ve(e)).join(`, `)})`:``;t.logStream.write(`Running: "${e.name} ${n}"${i}\n`)}let i=await Ue(r,{...t,logStream:n,nativeVerbose:e.verbose,positionalArguments:ze(e,t.positionalArguments)},e.parallel===!0);return{diagnostics:i.flatMap(({diagnostics:e})=>e),exitCode:+!i.every(({exitCode:e})=>e===0),machineOutcomes:i.flatMap(({machineOutcomes:e})=>e),name:e.name,tools:i.flatMap(({tools:e})=>e)}}catch(r){let i=String(r),a={durationMs:0,exitCode:1,name:e.name,unparsed:[i]};return t.format===`native`&&n.write(`${i}\n`),{diagnostics:[],exitCode:1,machineOutcomes:[{diagnostics:[],exitCode:1,tools:[a]}],name:e.name,tools:[a]}}}return t.scheduler.run(async()=>{if(Ae(e,t.format))return{diagnostics:[],exitCode:await(V(e)?Ce(t.logStream,t.positionalArguments,t.optionFlags,e,t.nativeVerbose):Te(t.logStream,t.positionalArguments,t.optionFlags,e,t.cache,t.nativeVerbose)),machineOutcomes:[],name:e.name,tools:[]};let n=await De(t.logStream,t.positionalArguments,t.optionFlags,e,t.cache);return{diagnostics:n.diagnostics,exitCode:n.exitCode,machineOutcomes:[n],name:e.name,tools:n.tools}})}async function Ue(e,t,n){if(!n||t.scheduler.concurrency===1){let n=[];for(let r of e)n.push(await He(r,t));return n}await Promise.resolve();let r=/* @__PURE__ */ new Map;for(let[t,n]of e.entries()){let e=n.stage??0,i=r.get(e)??[];i.push({command:n,index:t}),r.set(e,i)}let i=Array.from({length:e.length}),a=r.keys().toArray().toSorted((e,t)=>e-t);for(let e of a){let n=r.get(e)??[],a=await Promise.all(n.map(async({command:e,index:n})=>({index:n,outcome:await He(e,t)})));for(let{index:e,outcome:t}of a)i[e]=t}return i.filter(e=>e!==void 0)}function We(e,t,n,r,i){let a=[],o=[],s=Re(r,i);for(let e of t){let t=!H(e)||Re(r,e.positionalArgumentExtensions);!s||!t||n.includes(G(e.name))?o.push(e):a.push(e)}if(n.length>0){let r=new Set(o.map(e=>G(e.name))),i=n.filter(e=>!r.has(e));if(i.length>0){let n=t.map(e=>G(e.name)).join(`, `);e.write(`⚠️ ${E().yellow(`Unrecognized --skip ${z(`value`,i.length)}: ${i.join(`, `)}. Available: ${n}`)}\n`)}}return{commandsToRun:a,skippedCommands:o}}async function X(e,t,n,r,i,a,o,s=`native`){let c=typeof s==`string`?{}:s,l=typeof s==`string`?s:c.format??`native`,{commandsToRun:u,skippedCommands:d}=We(e,r,o??[],t,c.positionalArgumentExtensions),f=l===`native`&&i,{cache:p,scheduler:m}=await Pe(c),h=await Ue(u,{cache:p,format:l,logStream:e,nativeVerbose:f,optionFlags:n,positionalArguments:Y(t,c.positionalArgumentExtensions),scheduler:m},c.parallel===!0),g=h.map(({exitCode:e,name:t})=>({exitCode:e,name:t})),_=h.flatMap(({tools:e})=>e),ee=h.flatMap(({diagnostics:e})=>e);if(l===`machine`)for(let t of h)for(let n of t.machineOutcomes)je(e,n);let v=r.length,y=E();if(l===`native`&&d.length>0){let t=d.map(({name:e})=>e),n=y.bold(`${t.length} / ${v} ${z(`Command`,t.length)} Skipped:`);e.write(`⏭️ ${y.dim(n)} ${y.dim(t.join(`, `))}\n`)}if(l===`native`&&a){let t=g.filter(({exitCode:e})=>e===0).map(({name:e})=>e),n=g.filter(({exitCode:e})=>e!==0).map(({name:e})=>e);if(t.length>0){let n=y.bold(`${t.length} / ${v} ${z(`Command`,t.length)} Succeeded:`);e.write(`✅ ${y.green(n)} ${y.green(t.join(`, `))}\n`)}if(n.length>0){let t=y.bold(`${n.length} / ${v} ${z(`Command`,n.length)} Failed:`);e.write(`❌ ${y.red(t)} ${y.red(n.join(`, `))}\n`)}}return{exitCode:+!g.every(({exitCode:e})=>e===0),report:l===`json`?pe(_,ee):void 0}}async function Ge(e){let t=await s({cwd:e});return t===void 0?void 0:i.join(i.dirname(t),`init`)}async function Ke(e,r,a,o){let c=await s();if(c===void 0)throw Error("The `init` command must be used in a directory with a package.json file");let l=await Ge(import.meta.dirname);if(l===void 0)return e.write(`Error: Could not locate the package containing this CLI.
5
+ `),1;let u=i.dirname(c),d=(r===`file`||r===`package`)&&a!==void 0&&o!==void 0;try{if(d){let n=Object.keys(o)[0],i=t.readJsonSync(c);if(r===`package`){e.write(`Merging: \nPackage config key "${n}" → "${u}" (Because --location is set to "package")\n`);let r=j(i,o);t.writeJSONSync(c,r,{spaces:` `}),await I(c)}else n!==void 0&&Object.keys(i).includes(n)&&(e.write(`Deleting: \nPackage config key "${n}" in "${u}" (Because --location is set to "file")\n`),delete i[n],t.writeJSONSync(c,i,{spaces:` `}),await I(c))}if(!await t.pathExists(l))return 0;if((await t.readdir(l)).length===0)return e.write(`Source directory "${l}" is empty.\n`),0;e.write(`Adding initial configuration files from:\n"${l}" → "${u}"\n`),await t.copy(l,u,{async filter(o,s){let c=n.statSync(o).isFile(),l=n.existsSync(s);if(c){if(d&&r===`package`&&o.includes(a))return l?(e.write(`Deleting: \n"${o}" → "${s}" (Because --location is set to "package")\n`),t.removeSync(s)):e.write(`Skipping: \n"${o}" → "${s}" (Because --location is set to "package")\n`),!1;if(l&&(s.includes(`.vscode/`)||s.includes(`package.json`))&&i.extname(s)===`.json`){e.write(`Merging: \n"${o}" → "${s}"\n`);let n=t.readJSONSync(o),r=t.readJSONSync(s),i=s.endsWith(`.vscode/tasks.json`)?_e(r,n):j(r,n);return t.writeJSONSync(s,i,{spaces:` `}),await I(s),!1}return l?(e.write(`Overwriting: \n"${o}" → "${s}"\n`),await I(s),!0):(e.write(`Copying: \n"${o}" → "${s}"\n`),await I(s),!0)}return!0},overwrite:!0})}catch(e){return console.error(String(e)),1}return 0}async function qe(e){let{commands:{fix:t,init:n,lint:r,printConfig:i},description:a,logColor:o,logPrefix:s,name:c,showSummary:d,verbose:f}=e;oe();let p=R(s,o);p.pipe(T());let m=l(u(process.argv)).scriptName(c).usage(`$0 <command>`,a);n!==void 0&&m.command({builder(e){let t=n.locationOptionFlag?e.option(`location`,{choices:[`file`,`package`],default:`file`,describe:`Where to store the configuration.`,type:`string`}):e;return d?q(t):t},command:`init`,describe:n.description??`Initialize by copying starter config files to your project root${n.locationOptionFlag?` or to your package.json file.`:`.`}`,async handler(e){let t=n.locationOptionFlag?e.location:void 0,r=K(e.skip),{exitCode:i}=await X(p,[],t===void 0?[]:[`--location`,t],[{async execute(e,t,r){return Ke(e,r.at(1),n.configFile,n.configPackageJson)},name:`copyAndMergeInitFiles`},...n.commands??[]],void 0,void 0,r);process.exitCode=i}}),r!==void 0&&m.command({builder(e){let t=ke(J(r.positionalArgumentMode===`none`?e:e.positional(`files`,{array:!0,...r.positionalArgumentDefault!==void 0&&{default:r.positionalArgumentDefault},describe:`Files or glob pattern to lint.`,type:`string`})));return d?q(t):t},command:r.positionalArgumentMode===`none`?`lint`:r.positionalArgumentMode===`optional`?`lint [files..]`:`lint <files..>`,describe:r.description,async handler(e){let t=e.files??[],n=K(e.skip),i=C(),{exitCode:a,report:o}=await X(p,t,[],await B(r.commands),f,d,n,{cache:e.cache,format:i,parallel:r.parallel,positionalArgumentExtensions:r.positionalArgumentExtensions});o!==void 0&&process.stdout.write(`${k(o)}\n`),process.exitCode=a}}),t!==void 0&&m.command({builder(e){let n=ke(J(t.positionalArgumentMode===`none`?e:e.positional(`files`,{array:!0,...t.positionalArgumentDefault!==void 0&&{default:t.positionalArgumentDefault},describe:`Files or glob pattern to fix.`,type:`string`})));return d?q(n):n},command:t.positionalArgumentMode===`none`?`fix`:t.positionalArgumentMode===`optional`?`fix [files..]`:`fix <files..>`,describe:t.description,async handler(e){let n=e.files??[],r=K(e.skip),i=C(),{exitCode:a,report:o}=await X(p,n,[],await B(t.commands),void 0,void 0,r,{cache:e.cache,format:i,parallel:t.parallel,positionalArgumentExtensions:t.positionalArgumentExtensions});o!==void 0&&process.stdout.write(`${k(o)}\n`),process.exitCode=a}}),i!==void 0&&m.command({builder(e){let t=i.positionalArgumentMode===`none`?e:e.positional(`file`,{...i.positionalArgumentDefault!==void 0&&{default:i.positionalArgumentDefault},describe:`File or glob pattern to print configuration for.`,type:`string`});return d?q(t):t},command:i.positionalArgumentMode===`none`?`print-config`:i.positionalArgumentMode===`optional`?`print-config [file]`:`print-config <file>`,describe:i.description,async handler(e){let t=e.file??void 0,n=t===void 0?[]:[t],r=K(e.skip),{exitCode:a}=await X(p,n,[],await B(i.commands),f,d,r);process.exitCode=a}}),m.alias(`h`,`help`),m.version(re),m.alias(`v`,`version`),m.help(),m.wrap(process.stdout.isTTY?Math.min(120,m.terminalWidth()):0),await m.parseAsync()}const Z={fileRun:`Matches files below the current working directory by default.`,monorepoRun:`In a monorepo, it will also run in all packages below the current working directory.`,monorepoSearch:`Searches up to the root of a monorepo if necessary.`,multiArgumentCaveat:`Will use file arguments / globs where possible if provided, but some of the invoked tools only operate at the package scope.`,multiOptionCaveat:`Will use option flags where possible if provided, but some of the invoked tools will ignore them.`,optionalFileRun:`Package-scoped by default, file-scoped if a file argument is provided.`,packageRun:`Package-scoped.`,packageSearch:`Package-scoped.`},Je=[/Version 2\.0,?\s*January 2004/gv,/Version 1,?\s*February 1989/gv,/Version 2,?\s*June 1991/gv,/Version 3,?\s*29 June 2007/gv,/Version 2\.1,?\s*February 1999/gv,/Version 3,?\s*19 November 2007/gv,/Version 1\.0\s*-\s*August 17th,?\s*2003/gv,/Version 1\.1,?\s*March 2000/gv,/Version 1\.2,?\s*November 2002/gv,/Version 1\.3,?\s*3 November 2008/gv,/Version 1\.0\s*-\s*22 November 2005/gv,/Version 1\.1\s*-\s*26 February 2007/gv,/Version 2,?\s*December 2004/gv,/20 December 1996/gv,/December 20,?\s*1996/gv,/11 March 1996/gv,/28 March 2007/gv,/November 1,?\s*2008/gv,/August 1,?\s*2009/gv,/1 April 19\d{2}/gv,/Copyright \(c\) 2000-2006,?\s*The Perl Foundation/giv,/Copyright \(C\) (?:\d{4},?\s*)+Free Software Foundation/gv],Ye=[`node_modules/**`,`test/**`];function Xe(e){let t=e;for(let e of Je)e.lastIndex=0,t=t.replace(e,e=>e.replaceAll(/\d/gv,`X`));return t}const Ze=/(\d{4})\s*-\s*(\d{4})/v,Qe=/(\d{4})/v,$e=/\bcopyright\b|©/iv;function et(e){let t={start:0,end:e.length},n=0;for(let r of e.split(`
6
+ `))$e.test(r)&&Qe.test(r)&&(t={start:n,end:n+r.length}),n+=r.length+1;return t}function tt(e,t){let{start:n,end:r}=et(Xe(e)),i=nt(e.slice(n,r),t);return e.slice(0,n)+i+e.slice(r)}function nt(e,t){let n=Xe(e),r=Ze,i=r.exec(n);if(i){let[,n,a]=i;if(Number(a)!==t){let a=`${n}-${t}`;return e.slice(0,i.index)+e.slice(i.index).replace(r,()=>a)}return e}let a=Qe,o=a.exec(n);if(o){let[,n]=o;if(Number(n)!==t){let r=`${n}-${t}`;return e.slice(0,o.index)+e.slice(o.index).replace(a,()=>r)}return e}return e}async function rt(e){let t=(/* @__PURE__ */ new Date()).getFullYear(),n=[`**/license.txt`,`**/license`,...Ye.map(e=>`!${e}`)],r=await y(n,{caseSensitiveMatch:!1,cwd:N(),followSymbolicLinks:!1,gitignore:!0}),i=[];for(let n of r)try{let r=await v.readFile(n,`utf8`),a=tt(r,t);a!==r&&(i.push(n),e&&await v.writeFile(n,a,`utf8`))}catch(e){console.error(`Failed to process ${n}:`,e)}return i}async function it(e,t=!1){let n=await rt(t);if(n.length>0){e.write(`${t?`Fixed`:`Found`} ${n.length} license ${z(`file`,n.length)} with outdated copyright year:\n`);for(let t of n)e.write(` - ${t}\n`);return+!t}return 0}async function at(e){return it(e,!1)}async function ot(){let e=await rt(!1);return{diagnostics:e.map(e=>({file:D(e,N()),message:`License file has an outdated copyright year`,severity:`error`,tool:`copyright-year`})),exitCode:+(e.length>0),unparsed:[]}}async function st(e){return it(e,!0)}const Q=`pnpm-lock.yaml`;function ct(e){let n=P(),r=i.resolve(e);for(;;){if(t.existsSync(i.join(r,Q)))return r;if(r===n)break;let e=i.dirname(r);if(e===r)break;r=e}}function lt(e,t,n){let r=`${e}@${t}`;return Object.hasOwn(n,r)?r:Object.hasOwn(n,t)?t:void 0}function ut(e,t){return e===void 0||e===``?t===void 0||t===``?void 0:t:t===void 0||t===``||x(e,t)?e:t}async function dt(e){let t=ct(e);if(t===void 0||t===``)throw Error(`${Q} not found at or above "${e}".`);let n=i.join(t,Q),r=await ne(t,{ignoreIncompatible:!1});if(!r?.importers)throw Error(`Lockfile at "${n}" is unreadable or missing importers.`);let a=r.packages??{},o,s,c={},l={};function u(e,t){let n,r=/* @__PURE__ */ new Set;function i(e,t){if(t.startsWith(`link:`))return;let o=lt(e,t,a);if(o===void 0||o===``||r.has(o))return;r.add(o);let s=a[o];if(s===void 0)return;let c=s.engines?.node;if(c!==void 0&&c!==``){let e=te(c)?.version;e!==void 0&&e!==``&&(n===void 0||n===``||x(e,n))&&(n=e)}if(s.dependencies)for(let[e,t]of Object.entries(s.dependencies))i(e,t)}return i(e,t),n}function d(e,t){for(let[n,r]of Object.entries(e)){let e=u(n,typeof r==`string`?r:r.version);if(e===void 0||e===``)continue;let i=t?l:c;i[e]??=/* @__PURE__ */ new Set,i[e].add(n);let a=t?s:o;(a===void 0||a===``||x(e,a))&&(t?s=e:o=e)}}let f=i.relative(t,e),p=f===``?`.`:f,m=r.importers[p];m!==void 0&&(m.dependencies&&d(m.dependencies,!1),m.devDependencies&&d(m.devDependencies,!0));let h=ut(o,s),g=h===void 0?void 0:`>=${h}`;return{dependencies:o===void 0||o===``?void 0:{topLevelCauses:[...c[o]??[]],version:`>=${o}`},devDependencies:s===void 0||s===``?void 0:{topLevelCauses:[...l[s]??[]],version:`>=${s}`},lockfile:n,version:g}}function ft(e){let t=e.devEngines;if(t?.runtime)return(Array.isArray(t.runtime)?t.runtime:[t.runtime]).find(e=>e.name===`node`)?.version}function pt(e,t){let n=e.devEngines??{};if(n.runtime){if(Array.isArray(n.runtime)){let e=n.runtime.find(e=>e.name===`node`);e===void 0?n.runtime.push({name:`node`,version:t}):e.version=t}else n.runtime.name===`node`?n.runtime.version=t:n.runtime=[n.runtime,{name:`node`,version:t}]}else n.runtime={name:`node`,version:t};e.devEngines=n}function mt(e){let t=e.devEngines;if(t?.runtime){if(Array.isArray(t.runtime)){t.runtime=t.runtime.filter(e=>e.name!==`node`);let[e]=t.runtime;e===void 0?delete t.runtime:t.runtime.length===1&&(t.runtime=e)}else t.runtime.name===`node`&&delete t.runtime;Object.keys(t).length===0&&delete e.devEngines}}function $(e){return e.length===0?``:` (from ${e.join(`, `)})`}async function ht(e,n){let r=i.join(n,`package.json`);if(!t.existsSync(r))return{issues:[],packageJsonPath:r};let a=t.readJsonSync(r),o=a.engines?.node,s=ft(a),c=await dt(n),l=c.dependencies?.version,u=c.dependencies?.topLevelCauses??[],d=c.version,f=c.devDependencies?.topLevelCauses??[],p=[];if(l!==void 0){if(o===void 0){if(p.push(`Missing engines.node — suggest setting to "${l}"${$(u)}`),e){let e=a.engines??{};e.node=l,a.engines=e}}else{let t=b.minVersion(o),n=b.minVersion(l);t&&n&&b.lt(t,n)&&(p.push(`engines.node is "${o}" but production dependencies require at least "${l}"${$(u)}`),e&&(a.engines.node=l))}}let m=(()=>{if(l!==void 0&&l!==``&&o!==void 0&&o!==``){let e=b.minVersion(l),t=b.minVersion(o);if(e&&t)return b.gt(e,t)?l:o}return l??o})(),h=m===void 0||m===``?void 0:b.minVersion(m),g=d===void 0||d===``?void 0:b.minVersion(d),_=g&&h&&b.gt(g,h);if(d!==void 0&&_){if(s===void 0)p.push(`devDependencies require a higher Node.js minimum (${d}) than engines.node (${m??`none`}) — suggest adding devEngines.runtime for node with version "${d}"${$(f)}`),e&&pt(a,d);else{let t=b.minVersion(s);t&&b.lt(t,g)&&(p.push(`devEngines.runtime.version for node is "${s}" but all dependencies require at least "${d}"${$(f)}`),e&&pt(a,d))}}else if(s!==void 0){let t=b.minVersion(s);t&&h&&b.lte(t,h)&&(p.push(`devEngines.runtime.version for node is redundant (engines.node already covers the requirement) — suggest removing`),e&&mt(a))}return e&&p.length>0&&(t.writeJsonSync(r,a,{spaces:` `}),await I(r)),{issues:p,packageJsonPath:r}}async function gt(e,t){let n=ye(),r=0;for(let i of n){let{issues:n,packageJsonPath:a}=await ht(t,i);if(n.length!==0){e.write(`${t?`Fixed`:`Found`} ${n.length} Node.js version ${z(`issue`,n.length)} in ${a}:\n`);for(let t of n)e.write(` - ${t}\n`);t||(r=1)}}return r}async function _t(){let e=ye(),t=[];for(let n of e){let{issues:e,packageJsonPath:r}=await ht(!1,n);for(let n of e)t.push({file:D(r,process.cwd()),message:n,severity:`error`,tool:`node-version`})}return{diagnostics:t,exitCode:+(t.length>0),unparsed:[]}}async function vt(e){let t=k(await dt(N())).split(`
7
+ `);for(let n of t)e.write(`${n}\n`);return 0}async function yt(e){return gt(e,!1)}async function bt(e){return gt(e,!0)}await qe({commands:{fix:{commands:[{execute:st,name:`copyright-year`},{execute:bt,name:`node-version`}],description:`Fix common issues like outdated copyright years in license files. ${Z.packageRun} ${Z.monorepoRun}`,positionalArgumentMode:`none`},init:{locationOptionFlag:!1},lint:{commands:[{collect:ot,execute:at,name:`copyright-year`},{collect:_t,execute:yt,name:`node-version`}],description:`Check the repo for common issues. ${Z.packageRun} ${Z.monorepoRun}`,positionalArgumentMode:`none`},printConfig:{commands:[{execute:vt,name:`node-version`}],description:`Print minimum Node.js version constraints from the pnpm lockfile.`,positionalArgumentMode:`none`}},description:`Kitschpatrol's repository-related shared configuration tools.`,logColor:`gray`,logPrefix:`[Repo Config]`,name:`ksc-repo`,order:1});export{};
@@ -33,7 +33,7 @@ jobs:
33
33
  uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
34
34
 
35
35
  - name: Setup Node.js
36
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
36
+ uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
37
37
  with:
38
38
  node-version: 24
39
39
  cache: 'pnpm'
@@ -33,11 +33,11 @@ jobs:
33
33
 
34
34
  - name: Release Notes
35
35
  id: release-notes
36
- uses: kitschpatrol/github-action-release-changelog@12279a22cf9d0b432dca8ff189d82ad0dd393345 # v2.0.9
36
+ uses: kitschpatrol/github-action-release-changelog@5cc343b830037ae77937e9e66c31be0da5798efe # v2.0.10
37
37
 
38
38
  - name: Release
39
39
  id: release
40
- uses: kitschpatrol/github-action-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
40
+ uses: kitschpatrol/github-action-release@13b1829f4e449586eb63ed614e0429a684cb291c # v3.0.3
41
41
  with:
42
42
  token: ${{ secrets.PERSONAL_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}
43
43
  draft: false
@@ -3,7 +3,7 @@ name: Update Dependencies
3
3
  on:
4
4
  workflow_dispatch: {}
5
5
  schedule:
6
- - cron: '0 3 * * 1'
6
+ - cron: '0 3 1 * *'
7
7
 
8
8
  permissions:
9
9
  contents: read
@@ -22,7 +22,7 @@ jobs:
22
22
  uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
23
23
 
24
24
  - name: Setup Node.js
25
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
25
+ uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
26
26
  with:
27
27
  node-version: 24
28
28
  cache: 'pnpm'
@@ -34,6 +34,7 @@ jobs:
34
34
  uses: kitschpatrol/github-action-skill-to-pr@fe3e8b4aea5851133d8b064a68e92f7b7e4de1e4 # v1.1.1
35
35
  with:
36
36
  skill: ksc-update
37
+ title: Update dependencies.
37
38
  claude-code-oauth-token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
38
39
  github-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
39
40
  model: claude-opus-5-5
@@ -8,6 +8,9 @@ peerDependencyRules:
8
8
  # https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/issues/1075
9
9
  # https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/pull/1081
10
10
  eslint-plugin-jsx-a11y@6>eslint: ^10.0.0
11
+ permissions:
12
+ '@kitschpatrol/shared-config':
13
+ skills: true
11
14
  publicHoistPattern:
12
15
  - '@kitschpatrol/repo-config'
13
16
  - '@kitschpatrol/typescript-config'
@@ -19,3 +22,7 @@ publicHoistPattern:
19
22
  - '*remark*'
20
23
  - '*stylelint*'
21
24
  - 'case-police'
25
+ skills:
26
+ dirs:
27
+ - .agents/skills
28
+ - .claude/skills
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitschpatrol/repo-config",
3
- "version": "8.13.1",
3
+ "version": "8.14.0",
4
4
  "description": "Repository configuration and GitHub workflows for @kitschpatrol/shared-config.",
5
5
  "keywords": [
6
6
  "shared-config",
@@ -30,23 +30,24 @@
30
30
  },
31
31
  "files": [
32
32
  "bin/*",
33
- "init/*"
33
+ "init/*",
34
+ "init/.gitignore"
34
35
  ],
35
36
  "dependencies": {
36
37
  "@pinojs/json-colorizer": "^4.0.0",
37
- "@pnpm/lockfile.fs": "^1100.2.13",
38
+ "@pnpm/lockfile.fs": "^1100.2.14",
38
39
  "cosmiconfig": "^10.0.1",
39
40
  "cosmiconfig-typescript-loader": "^6.3.0",
40
41
  "decircular": "^1.0.0",
41
42
  "deepmerge": "^4.3.1",
42
- "execa": "^10.1.0",
43
+ "execa": "^10.2.1",
43
44
  "find-workspaces": "^0.3.1",
44
45
  "fs-extra": "^11.4.1",
45
46
  "globby": "^16.2.4",
46
47
  "json-stringify-pretty-compact": "^4.0.0",
47
48
  "package-up": "^5.0.0",
48
49
  "picocolors": "^1.1.1",
49
- "prettier": "^3.9.9",
50
+ "prettier": "^3.9.10",
50
51
  "semver": "^7.8.5",
51
52
  "yargs": "^18.2.0"
52
53
  },
package/readme.md CHANGED
@@ -37,7 +37,7 @@ This includes the following:
37
37
  - `set-github-metadata.yml` Populates GitHub repo metadata from package.json
38
38
  - `ci.yml` Basic cross-platform CI action
39
39
  - `check-links.yml` Checks links in Markdown files and on the project's homepage weekly
40
- - `update-dependencies.yml` Runs the `ksc-update` skill with Claude Code weekly or on demand, then opens a pull request with the changes and the skill's report (see [Dependency updates](#dependency-updates))
40
+ - `update-dependencies.yml` Runs the `ksc-update` skill with Claude Code monthly or on demand, then opens a pull request with the changes and the skill's report (see [Dependency updates](#dependency-updates))
41
41
 
42
42
  In order to work around some hoisting issues related to plugin resolution in the other `@kitschpatrol/shared-config` packages, it's critical that it is applied _before_ any other `@kitschpatrol/shared-config` packages are installed.
43
43
 
@@ -113,7 +113,13 @@ If you want releases to come from your account instead of `github_actions`, then
113
113
 
114
114
  #### Dependency updates
115
115
 
116
- The `update-dependencies.yml` workflow runs the [`ksc-update`](https://github.com/kitschpatrol/shared-config/blob/main/packages/shared-config/skills/ksc-update/SKILL.md) skill through [Claude Code](https://code.claude.com/docs/en/github-actions) every Sunday night, or on demand from the repository's _Actions_ tab, then opens a pull request with the changes and the skill's report. The skill ships with `@kitschpatrol/shared-config` and is synced from `node_modules` before each run with the [skills CLI](https://github.com/vercel-labs/skills). The workflow fails if no `ksc-update` skill is found.
116
+ The `update-dependencies.yml` workflow runs the [`ksc-update`](https://github.com/kitschpatrol/shared-config/blob/main/packages/shared-config/skills/ksc-update/SKILL.md) skill through [Claude Code](https://code.claude.com/docs/en/github-actions) every Sunday night, or on demand from the repository's _Actions_ tab, then opens a pull request with the changes and the skill's report. The skill ships with `@kitschpatrol/shared-config`, and pnpm links it into `.agents/skills` and `.claude/skills` during install because the starter `pnpm-workspace.yaml` approves the package's [agent skills](https://pnpm.io/agent-skills). The workflow fails if no `ksc-update` skill is found.
117
+
118
+ The pull request is titled `Update dependencies.`, so GitHub's _Default to pull request title_ squash merge setting produces commits like `Update dependencies. (#12)` without the report in the body. Enable it once per repository:
119
+
120
+ ```sh
121
+ gh api -X PATCH repos/{owner}/{repo} -f squash_merge_commit_title=PR_TITLE -f squash_merge_commit_message=BLANK
122
+ ```
117
123
 
118
124
  Claude runs with the read-only `GITHUB_TOKEN` and can't push, so the workflow needs two secrets:
119
125
 
@@ -1,113 +0,0 @@
1
- ---
2
- name: ksc
3
- description: Code conventions and lint workflow for projects that use @kitschpatrol/shared-config and its ksc CLI, which wraps ESLint, Prettier, TypeScript, Stylelint, CSpell, Knip, remark, and mdat. Use when writing or editing TypeScript, JavaScript, CSS, Markdown, JSON, or YAML in a project that depends on @kitschpatrol/shared-config, when running or fixing `ksc lint` / `ksc fix` failures, when writing eslint-disable comments, or when editing the tool config files it manages.
4
- license: MIT
5
- ---
6
-
7
- # Working with @kitschpatrol/shared-config
8
-
9
- The project lints, formats, and type checks through the `ksc` CLI. The rules are strict and warnings fail the run, so write code that matches the conventions below, then let the tools fix what they can.
10
-
11
- ## Workflow
12
-
13
- 1. Write the code.
14
- 2. Run `pnpm ksc fix`. It applies every auto-fix (formatting, sorting, import style), then reports what remains.
15
- 3. Fix the remaining issues by hand and repeat until `pnpm ksc lint` is clean.
16
-
17
- Use pnpm, not npm, npx, or yarn. Projects usually map `pnpm lint` and `pnpm fix` to the commands above.
18
-
19
- Both commands accept file arguments (`pnpm ksc fix src/thing.ts`) and `--skip <tool>`. Tools that only work on the whole package, such as TypeScript and Knip, ignore file arguments. To work on one tool's errors, run it alone:
20
-
21
- | Command | Tool | `lint` | `fix` |
22
- | ---------------- | ----------------------------------- | ------ | ----- |
23
- | `ksc-eslint` | ESLint, including Markdown linting | yes | yes |
24
- | `ksc-prettier` | Prettier | yes | yes |
25
- | `ksc-typescript` | Type checking | yes | |
26
- | `ksc-stylelint` | Stylelint | yes | yes |
27
- | `ksc-cspell` | Spelling and letter case | yes | yes |
28
- | `ksc-knip` | Unused files, exports, dependencies | yes | |
29
- | `ksc-mdat` | Readme placeholder comments | yes | yes |
30
-
31
- `pnpm ksc print-config [file]` shows the resolved configuration when a rule's settings are unclear.
32
-
33
- ## Gotchas
34
-
35
- - **Do not sort or format by hand.** Prettier owns formatting, and the Perfectionist ESLint plugin sorts imports, object keys, type members, and unions. `fix` handles both. Some keys intentionally sort semantically instead of alphabetically (`x, y, z`, `width, height`, `min, max`, `start, end`, `r, g, b, a`), so leave whatever order `fix` produces.
36
- - **ESLint plugins are renamed.** Disable comments must use the short prefix, e.g. `// eslint-disable-next-line ts/no-explicit-any`:
37
-
38
- | Upstream name | Prefix here |
39
- | ----------------------------------- | ----------------- |
40
- | `@typescript-eslint` | `ts` |
41
- | `import-x` | `import` |
42
- | `n` | `node` |
43
- | `vitest` | `test` |
44
- | `@eslint-community/eslint-comments` | `eslint-comments` |
45
- | `@eslint-react` | `react` |
46
- | `@stylistic` | `stylistic` |
47
- | `jsonc` | `json` |
48
- | `yml` | `yaml` |
49
- | `@html-eslint` | `html` |
50
- | `package-json` | `json-package` |
51
-
52
- - **Unknown words fail CSpell.** Add legitimate project terms to the `words` array in `cspell.config.ts`. An unscoped `ksc fix` removes words that are no longer used anywhere.
53
- - **Knip flags anything unused**, including exports, files, and dependencies. Remove dead code instead of leaving it exported.
54
- - **Generated readme sections are owned by mdat.** Content between `<!-- keyword -->` and `<!-- /keyword -->` comments is regenerated by `ksc fix`. Do not edit it by hand.
55
- - **ESLint is type-aware and never cached**, so it is the slow step. `--no-cache` disables the other tools' caches if results look stale.
56
-
57
- ## TypeScript rules that fail most often
58
-
59
- - **No `null`.** Use `undefined` (`unicorn/no-null`, `ts/no-restricted-types`). Convert at API boundaries: `apiResult() ?? undefined`. Comparing against `null` with `===` is allowed.
60
- - **No `any`.** Use `unknown` and narrow (`ts/no-explicit-any`, plus `ts/no-unsafe-assignment`, `-call`, `-member-access`, `-return`).
61
- - **No `Buffer` or `object` types.** Use `Uint8Array` and `Record<string, unknown>`.
62
- - **Handle every promise** (`ts/no-floating-promises`). Use `await`, or `void someAsyncFunction()` for deliberate fire-and-forget. Functions that return a promise must be declared `async` (`ts/promise-function-async`).
63
- - **Template literals accept only strings and numbers** (`ts/restrict-template-expressions`). Convert the rest: `` `ready: ${String(isReady)}` ``. `+` cannot mix strings and numbers (`ts/restrict-plus-operands`).
64
- - **Conditions must be boolean** (`ts/strict-boolean-expressions`). Strings and numbers are not allowed as conditions, so write `text !== ''` and `array.length > 0` (`unicorn/explicit-length-check`). Nullable objects and nullable booleans are allowed.
65
- - **Use `??` and `?.`** instead of `||` and `&&` chains for nullish values (`ts/prefer-nullish-coalescing`, `ts/prefer-optional-chain`).
66
- - **Indexed access is `T | undefined`** (`noUncheckedIndexedAccess`). Narrow `array[i]` and `record[key]` before use.
67
- - **Only erasable syntax** (`erasableSyntaxOnly`). No `enum`, runtime `namespace`, or constructor parameter properties.
68
- - **Type-only imports and exports use separate top-level statements** (`verbatimModuleSyntax`, `import/consistent-type-specifier-style`): `import type { Foo } from './bar'` and `export type { Foo }`, never the inline `import { type Foo }`.
69
- - **`type`, not `interface`** (`ts/consistent-type-definitions`).
70
- - **Array types:** `string[]` for simple element types, `Array<string | number>` for anything else (`ts/array-type`).
71
- - **Unused locals and parameters are errors.** Prefix intentionally unused ones with `_`.
72
- - **Every code path returns** (`noImplicitReturns`), and overriding class members need `override`.
73
-
74
- ## Naming
75
-
76
- Enforced by `ts/naming-convention` and unicorn:
77
-
78
- - `camelCase` for variables, functions, parameters, and properties. `const` variables may also be `UPPER_CASE`.
79
- - `StrictPascalCase` for types, classes, and type parameters. Strict means `HttpClient`, not `HTTPClient`.
80
- - Imports and destructured variables may be `camelCase` or `StrictPascalCase`.
81
- - Properties that need quotes (e.g. `'Content-Type'`) are exempt.
82
- - File names are `kebab-case` (`unicorn/filename-case`).
83
- - No abbreviations (`unicorn/name-replacements`): `error` not `err`, `button` not `btn`, `index` not `idx`. The exceptions are `i`, `j`, `acc`, `arg`, `args`, `db`, `dev`, `doc`, `docs`, `env`, `fn`, `lib`, `param`, `params`, `pkg`, `prop`, `props`, `ref`, `refs`, `sep`, `src`, `temp`, `util`, and `utils`.
84
- - Catch clause variables are named `error` (`unicorn/catch-error-name`).
85
-
86
- ## Style
87
-
88
- Prettier settings: no semicolons, single quotes, tabs (spaces in Markdown and YAML), trailing commas, 100 column width, LF line endings.
89
-
90
- ESLint rules that are not auto-fixed or that change how code is written:
91
-
92
- - Braces on every `if`, `else`, and loop body (`curly`).
93
- - `for...of` instead of `.forEach()` (`unicorn/no-for-each`). `.reduce()` is allowed only for simple operations like sums (`unicorn/no-array-reduce`).
94
- - `node:` protocol for Node.js built-ins: `import fs from 'node:fs'`.
95
- - Comments start with a capital letter (`capitalized-comments`).
96
- - Exported function declarations need a JSDoc comment with a description (`jsdoc/require-jsdoc`, `jsdoc/require-description`). Do not write types in JSDoc, so `@param name` not `@param {string} name`. `@param` and `@returns` tags are optional in TypeScript files.
97
-
98
- ## Configuration files
99
-
100
- Each tool is configured through a typed factory function. Pass overrides to the factory instead of replacing the shared config:
101
-
102
- | File | Contents |
103
- | --------------------- | ------------------------------------------------------------- |
104
- | `eslint.config.ts` | `eslintConfig()` from `@kitschpatrol/eslint-config` |
105
- | `prettier.config.ts` | `prettierConfig()` from `@kitschpatrol/prettier-config` |
106
- | `cspell.config.ts` | `cspellConfig()` from `@kitschpatrol/cspell-config` |
107
- | `knip.config.ts` | `knipConfig()` from `@kitschpatrol/knip-config` |
108
- | `stylelint.config.js` | `stylelintConfig()` from `@kitschpatrol/stylelint-config` |
109
- | `.remarkrc.js` | `remarkConfig()` from `@kitschpatrol/remark-config` |
110
- | `mdat.config.ts` | `mdatConfig()` from `@kitschpatrol/mdat-config` |
111
- | `tsconfig.json` | `"extends": "@kitschpatrol/typescript-config"` (TypeScript 6) |
112
-
113
- Configs may instead live under the matching keys in `package.json`. `eslintConfig()` detects Astro, React, and Svelte from installed packages. Pass `{ astro: true }`, `{ react: true }`, or `{ svelte: true }` to force one on. Per-file rule overrides go in the factory's options, e.g. `eslintConfig({ ts: { overrides: { 'ts/no-explicit-any': 'off' } } })`.