denvig 0.2.0 → 0.3.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/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Denvig - Developer Environment Invigorator
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/denvig?color=yellow)](https://npmjs.com/package/denvig)
4
+ [![install size](https://packagephobia.com/badge?p=denvig)](https://packagephobia.com/result?p=denvig)
5
+
3
6
  Denvig is a concept of simplifying development environments across multiple languages and frameworks by creating a small
4
7
  set of consistent wrappers to avoid muscle memory and configuration headaches.
5
8
 
@@ -59,7 +62,7 @@ can be supported by using the per project configs.
59
62
  - [ ] NextJS
60
63
  - [ ] Ruby
61
64
  - [ ] Rails
62
- - [ ] Python
65
+ - [x] Python
63
66
 
64
67
 
65
68
 
package/dist/cli.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var he=Object.create;var L=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var $e=Object.getPrototypeOf,De=Object.prototype.hasOwnProperty;var m=(e,n)=>()=>(e&&(n=e(e=0)),n);var q=(e,n)=>{for(var o in n)L(e,o,{get:n[o],enumerable:!0})},ve=(e,n,o,s)=>{if(n&&typeof n=="object"||typeof n=="function")for(let t of be(n))!De.call(e,t)&&t!==o&&L(e,t,{get:()=>n[t],enumerable:!(s=ye(n,t))||s.enumerable});return e};var Ce=(e,n,o)=>(o=e!=null?he($e(e)):{},ve(n||!e||!e.__esModule?L(o,"default",{value:e,enumerable:!0}):o,e));var g,Ae,W,N,H,M=m(()=>{"use strict";g=require("zod"),Ae=["build","check-types","dev","install","lint","outdated","test"],W=g.z.object({}),N=W.extend({codeRootDir:g.z.string().describe("The root directory where all code is stored"),quickActions:g.z.array(g.z.string()).default(Ae).optional().describe("Actions that are available on the CLI root for quick access")}),H=W.extend({name:g.z.string().describe("Unique identifier for the project"),actions:g.z.record(g.z.string().describe("Name of the action"),g.z.object({command:g.z.string().describe("Shell command to run for the action")})).optional().describe("Actions that can be run against the project"),quickActions:g.z.array(g.z.string()).optional().describe("Actions that are available on the CLI root for quick access")})});var U,xe,_,z=m(()=>{"use strict";U=require("fs"),xe=require("fs/promises"),_=e=>{try{return(0,U.readFileSync)(e,"utf8").trim()||null}catch(n){if(n&&typeof n=="object"&&"code"in n&&n.code==="ENOENT")return null;throw n}}});var D,I,S,Pe,B,b,K,F=m(()=>{"use strict";D=require("path"),I=require("yaml");M();z();S=(0,D.resolve)(process.env.DENVIG_GLOBAL_CONFIG_PATH||`${process.env.HOME}/.denvig/config.yml`),Pe=(0,D.resolve)(process.env.DENVIG_CODE_ROOT_DIR||`${process.env.HOME}/src`),B={codeRootDir:Pe,quickActions:void 0},b=()=>{let e=_(S);if(e){let n=(0,I.parse)(e)||{};try{if(n.codeRootDir?.startsWith(".")){let o=(0,D.dirname)(S);n.codeRootDir=(0,D.resolve)(`${o}/${n.codeRootDir}`)}return{...N.parse({...B,...n}),$sources:[S]}}catch(o){console.error(`Error parsing global config at ${S}:`,o),process.exit(1)}}return{...N.parse(B),$sources:[]}},K=e=>{let n=b(),o={name:e,actions:{}},s=`${n.codeRootDir}/${e}/.denvig.yml`,t=_(s);if(t)try{return{...o,...H.parse((0,I.parse)(t)),$sources:[s]}}catch(i){console.warn(`Error parsing project config for ${e} at ${s}.`),i instanceof Error?console.warn(i.message):console.warn("Unknown error:",i)}return{...o,$sources:[]}}});var ee,Z=m(()=>{ee={name:"denvig",version:"0.2.0",license:"MIT",description:"A CLI tool to consistently manage cross-discipline projects",bin:{denvig:"./dist/cli.cjs"},type:"module",files:["dist/","LICENSE","README.md"],scripts:{build:"rm -rf dist && tsup","check-types":"tsc --noEmit",prepublishOnly:"npm run build",lint:"biome check","lint:fix":"biome check --fix",test:"node --test src/**/*.test.ts","test:ci":"node --test src/**/*.test.ts --reporter=default",dev:"tsc --watch"},dependencies:{minimist:"^1.2.8",yaml:"^2.4.5",zod:"^4.0.14"},devDependencies:{"@biomejs/biome":"^2.1.3","@types/minimist":"^1.2.5","@types/node":"^22",tsup:"^8.5.0",typescript:"^5.0.0"},engines:{node:">=22"},repository:{type:"git",url:"git+https://github.com/marcqualie/denvig.git"},keywords:["cli","node","developer-tools","productivity","typescript"]}});function v(){return ee.version}var O=m(()=>{"use strict";Z()});var y,w=m(()=>{"use strict";y=class{name;description;usage;example;args;flags;handler;constructor(n){this.name=n.name,this.description=n.description||"",this.usage=n.usage,this.example=n.example,this.args=n.args,this.flags=n.flags,this.handler=n.handler}async run(n,o,s,t){try{return await this.handler({project:n,args:o,flags:s,extraArgs:t})}catch(i){return console.error(`Error executing command "${this.name}":`,i),{success:!1,message:"fail"}}}}});var oe={};q(oe,{runCommand:()=>ke});var ne,ke,te=m(()=>{"use strict";ne=require("child_process");w();O();ke=new y({name:"run",description:"Run an action from the project. If no action is specified, lists available actions.",usage:"run [action]",example:"run build",args:[{name:"action",description:"The action to run (e.g. build, test, deploy)",required:!1,type:"string"}],flags:[],handler:async({project:e,args:n,extraArgs:o=[]})=>{if(!n.action){console.log(`Denvig v${v()}`),console.log(""),console.log("Usage: denvig run [action] [...actionArgs]"),console.log(""),console.log("Available actions:");for(let l in e.actions){if(!e.actions[l])continue;let A=e.actions[l].split(`
3
- `),T=A[0],x=A.slice(1);console.log(` ${l}: ${T}`);for(let P of x)P.trim()&&console.log(`${" ".repeat(l.length+4)}${P}`)}return{success:!0,message:"No action specified."}}let s=e.actions[n.action];if(!s)return console.error(`Action "${n.action}" not found in project ${e.name}.`),{success:!1,message:`Action "${n.action}" not found.`};let t=`${s} ${o.join(" ")}`.trim();console.log(`$ ${t}`);let i={...process.env,DENVIG_PROJECT:e.slug},d=process.stdout.isTTY&&process.stdin.isTTY,a,p;d?process.platform==="darwin"?(a="script",p=["-q","/dev/null","sh","-c",t]):(a="script",p=["-q","-c",t,"/dev/null"]):(a="sh",p=["-c",t]);let G=(0,ne.spawn)(a,p,{cwd:e.path,env:i,stdio:"inherit"});return await new Promise(l=>{G.on("close",u=>{l({success:u===0})})})}})});var E,se=m(()=>{"use strict";E=e=>e.replace(process.env.HOME||"/root","~")});var ce={};q(ce,{configCommand:()=>Se});var re,ie,Se,ae=m(()=>{"use strict";re=require("yaml");w();F();se();ie=e=>{let n=Object.fromEntries(Object.entries({...e,$sources:void 0}).filter(([o,s])=>s!==void 0));(0,re.stringify)(n,{indent:2,lineWidth:80}).trim().split(`
4
- `).map(o=>console.log(` ${E(o)}`))},Se=new y({name:"config",description:"Display the current global and project configuration.",usage:"config",example:"config",args:[],flags:[],handler:({project:e})=>{let n=b(),o=e.config;return console.log("Denvig Config"),console.log(""),console.log(`Global: ${n.$sources.map(s=>E(s)).join(", ")||"default"}`),ie(n),console.log(""),console.log(`Project: ${e.config.$sources.map(s=>E(s)).join(", ")||"default"}`),console.log(` slug: ${e.slug}`),ie(o),{success:!0,message:"Configuration displayed."}}})});var le={};q(le,{versionCommand:()=>Fe});var Fe,ge=m(()=>{"use strict";w();O();Fe=new y({name:"version",description:"Show the current version of Denvig",usage:"version",example:"denvig version",args:[],flags:[],handler:()=>(console.log(`v${v()}`),{success:!0})})});var V=Ce(require("minimist"),1);F();var f=require("fs"),Y=e=>{let n=e.dependencies,o={};if(e.config.actions&&(o={...o,...Object.entries(e.config.actions).reduce((s,[t,i])=>(s[t]=i.command,s),{})}),n.some(s=>s.name==="deno")){let t=((0,f.existsSync)(`${e.path}/deno.json`)?JSON.parse((0,f.readFileSync)(`${e.path}/deno.json`,"utf8")):(0,f.existsSync)(`${e.path}/deno.jsonc`)?JSON.parse((0,f.readFileSync)(`${e.path}/deno.jsonc`,"utf8")):{}).tasks||{};o=Q(o,{...o,test:t?.test?"deno task test":"deno test",lint:t?.lint?"deno task lint":"deno lint","check-types":t?.checkTypes?"deno task check-types":"deno check",...Object.entries(t).reduce((i,[d,a])=>(i[d]=a.startsWith("deno")?a:`deno task ${d}`,i),{}),install:"deno install",outdated:"deno outdated"})}if(n.some(s=>s.name==="npm")){let t=JSON.parse((0,f.readFileSync)(`${e.path}/package.json`,"utf8")).scripts||{},i="npm";(0,f.existsSync)(`${e.path}/pnpm-lock.yaml`)?i="pnpm":(0,f.existsSync)(`${e.path}/yarn.lock`)&&(i="yarn"),o=Q(o,{build:`${i} ${t.build||"run build"}`,test:`${i} ${t.test||"run test"}`,lint:`${i} ${t.lint||"run lint"}`,dev:`${i} ${t.dev||"run dev"}`,...Object.entries(t).reduce((d,[a,p])=>(d[a]=p.startsWith(i)?p:`${i} run ${a}`,d),{}),install:`${i} install`,outdated:`${i} outdated`})}return o},Q=(e,n)=>{for(let[o,s]of Object.entries(n))e[o]||(e[o]=s);return e};F();var h=require("fs"),X=e=>{let n=[];if((0,h.existsSync)(`${e.path}/package.json`)){n.push({id:"npm:npm",name:"npm",ecosystem:"system",versions:[]});let o=JSON.parse((0,h.readFileSync)(`${e.path}/package.json`,"utf8"));if(o.dependencies)for(let[s,t]of Object.entries({...o.dependencies,...o.devDependencies}))n.push({id:`npm:${s}`,name:s,ecosystem:"npm",versions:Array.isArray(t)?t:[t]})}return(0,h.existsSync)(`${e.path}/yarn.lock`)&&n.push({id:"npm:yarn",name:"yarn",ecosystem:"system",versions:[]}),(0,h.existsSync)(`${e.path}/pnpm-lock.yaml`)&&n.push({id:"npm:pnpm",name:"pnpm",ecosystem:"system",versions:[]}),((0,h.existsSync)(`${e.path}/deno.json`)||(0,h.existsSync)(`${e.path}/deno.jsonc`))&&n.push({id:"deno:deno",name:"deno",ecosystem:"system",versions:[process.version]}),n};var R=class{slug;config;constructor(n){this.slug=n,this.config=K(n)}get name(){return this.config.name}get path(){return`${b().codeRootDir}/${this.slug}`}get dependencies(){return X(this)}get actions(){return Y(this)}};O();var de=[{name:"project",description:"The project slug to run against. Defaults to current directory.",required:!1,type:"string",defaultValue:void 0}];async function Re(){let e=process.argv[2],n=process.argv.slice(2),o=b(),s=process.cwd(),t=(0,V.default)(process.argv.slice(2)).project?.toString()||s.replace(`${o.codeRootDir}/`,"").split("/").slice(0,2).join("/"),i=new R(t),d=[...o.quickActions||[],...i?.config?.quickActions||[]].sort();d.includes(e)&&(n=["run",...process.argv.slice(2)],e="run",console.log("> Proxying to denvig run",...process.argv.slice(2)));let{runCommand:a}=await Promise.resolve().then(()=>(te(),oe)),{configCommand:p}=await Promise.resolve().then(()=>(ae(),ce)),{versionCommand:G}=await Promise.resolve().then(()=>(ge(),le)),$={run:a,config:p,version:G},l=$[e],u=(0,V.default)(n),A=l?.args.reduce((c,r,k)=>{let C=u._[k+1];return C!==void 0?c[r.name]=C:r.required&&(console.error(`Missing required argument: ${r.name}`),process.exit(1)),c},{})||{},T=u._.slice(l?.args.length+1).map(c=>String(c))||[],x=[...de,...l?.flags||[]],P=new Set(x.map(c=>c.name)),me=x.reduce((c,r)=>(u[r.name]!==void 0?c[r.name]=u[r.name]:r.defaultValue!==void 0?c[r.name]=r.defaultValue:r.required&&(console.error(`Missing required flag: ${r.name}`),process.exit(1)),c),{}),j=[];for(let[c,r]of Object.entries(u))c!=="_"&&!P.has(c)&&(r===!0?j.push(`--${c}`):r===!1?j.push(`--no-${c}`):j.push(`--${c}`,String(r)));let pe=[...T,...j];e||(console.log(`Denvig v${v()}`),console.log(""),console.log("Usage: denvig <command> [args] [flags]"),console.log(""),console.log("Available commands:"),Object.keys($).forEach(r=>{console.log(` - ${$[r].usage.padEnd(20," ")} ${$[r].description}`)}),console.log(""),console.log("Quick Actions:"),d.forEach(r=>{let k=i?.actions?.[r];if(!k){console.log(` - ${r.padEnd(20," ")} not defined`);return}let C=k.split(`
5
- `),fe=C[0],ue=C.slice(1);console.log(` - ${r.padEnd(20," ")} $ ${fe}`);for(let J of ue)J.trim()&&console.log(`${" ".repeat(27)}${J}`)}),console.log(""),console.log("Global flags:"),de.forEach(r=>{console.log(` --${r.name.padEnd(20," ")} ${r.description}`)}),process.exit(1)),$[e]||(console.error(`Command "${e}" not found.`),process.exit(1));try{t||console.error("No project provided or detected.");let{success:c}=await l.run(i,A,me,pe);c||process.exit(1)}catch(c){console.error(`Error executing command "${e}":`,c),process.exit(1)}}Re();
2
+ "use strict";var Be=Object.create;var U=Object.defineProperty;var Ke=Object.getOwnPropertyDescriptor;var Qe=Object.getOwnPropertyNames;var Xe=Object.getPrototypeOf,Ze=Object.prototype.hasOwnProperty;var a=(n,e)=>()=>(n&&(e=n(n=0)),e);var w=(n,e)=>{for(var o in e)U(n,o,{get:e[o],enumerable:!0})},en=(n,e,o,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Qe(e))!Ze.call(n,s)&&s!==o&&U(n,s,{get:()=>e[s],enumerable:!(t=Ke(e,s))||t.enumerable});return n};var D=(n,e,o)=>(o=n!=null?Be(Xe(n)):{},en(e||!n||!n.__esModule?U(o,"default",{value:n,enumerable:!0}):o,n));var h,nn,oe,V,te,se=a(()=>{"use strict";h=require("zod"),nn=["build","check-types","dev","install","lint","outdated","test"],oe=h.z.object({}),V=oe.extend({codeRootDir:h.z.string().describe("The root directory where all code is stored"),quickActions:h.z.array(h.z.string()).default(nn).optional().describe("Actions that are available on the CLI root for quick access")}),te=oe.extend({name:h.z.string().describe("Unique identifier for the project"),actions:h.z.record(h.z.string().describe("Name of the action"),h.z.object({command:h.z.string().describe("Shell command to run for the action")})).optional().describe("Actions that can be run against the project"),quickActions:h.z.array(h.z.string()).optional().describe("Actions that are available on the CLI root for quick access")})});var ie,on,W,re=a(()=>{"use strict";ie=require("fs"),on=require("fs/promises"),W=n=>{try{return(0,ie.readFileSync)(n,"utf8").trim()||null}catch(e){if(e&&typeof e=="object"&&"code"in e&&e.code==="ENOENT")return null;throw e}}});var R,z,N,tn,ce,$,ae,G=a(()=>{"use strict";R=require("path"),z=require("yaml");se();re();N=(0,R.resolve)(process.env.DENVIG_GLOBAL_CONFIG_PATH||`${process.env.HOME}/.denvig/config.yml`),tn=(0,R.resolve)(process.env.DENVIG_CODE_ROOT_DIR||`${process.env.HOME}/src`),ce={codeRootDir:tn,quickActions:void 0},$=()=>{let n=W(N);if(n){let e=(0,z.parse)(n)||{};try{if(e.codeRootDir?.startsWith(".")){let o=(0,R.dirname)(N);e.codeRootDir=(0,R.resolve)(`${o}/${e.codeRootDir}`)}return{...V.parse({...ce,...e}),$sources:[N]}}catch(o){console.error(`Error parsing global config at ${N}:`,o),process.exit(1)}}return{...V.parse(ce),$sources:[]}},ae=n=>{let e=$(),o={name:n,actions:{}},t=`${e.codeRootDir}/${n}/.denvig.yml`,s=W(t);if(s)try{return{...o,...te.parse((0,z.parse)(s)),$sources:[t]}}catch(i){console.warn(`Error parsing project config for ${n} at ${t}.`),i instanceof Error?console.warn(i.message):console.warn("Unknown error:",i)}return{...o,$sources:[]}}});var _,Y=a(()=>{"use strict";_=(n,e)=>{for(let[o,t]of Object.entries(e))n[o]||(n[o]=[]),n[o].push(...t);return n}});var B,P,O=a(()=>{"use strict";B=D(require("fs"),1),P=n=>{let e=`${n.path}/package.json`;if(!B.default.existsSync(e))return null;let o=B.default.readFileSync(e,"utf-8");return JSON.parse(o)}});var y,x=a(()=>{"use strict";y=n=>n});var j,sn,le,ge=a(()=>{"use strict";j=D(require("fs"),1);Y();O();x();sn=y({name:"deno",actions:async n=>{let e=j.default.readdirSync(n.path);if(!(e.includes("deno.json")||e.includes("deno.jsonc")))return{};let s=P(n)?.scripts||{},i={...Object.entries(s).map(([g,p])=>[g,`deno ${p}`]).reduce((g,[p,m])=>(g[p]=[m],g),{}),install:["deno install"],outdated:["deno outdated"]},r=((0,j.existsSync)(`${n.path}/deno.json`)?JSON.parse((0,j.readFileSync)(`${n.path}/deno.json`,"utf8")):(0,j.existsSync)(`${n.path}/deno.jsonc`)?JSON.parse((0,j.readFileSync)(`${n.path}/deno.jsonc`,"utf8")):{}).tasks||{};return i=_(i,{test:[r?.test?"deno task test":"deno test"],lint:[r?.lint?"deno task lint":"deno lint"],"check-types":[r?.checkTypes?"deno task check-types":"deno check"],...Object.entries(r).reduce((g,[p,m])=>(g[p]=[m.startsWith("deno")?m:`deno task ${p}`],g),{}),install:["deno install"],outdated:["deno outdated"]}),i}}),le=sn});var pe,rn,de,me=a(()=>{"use strict";pe=D(require("fs"),1);O();x();rn=y({name:"npm",actions:async n=>{let e=pe.default.readdirSync(n.path),o=e.includes("package.json"),t=e.includes("pnpm-lock.yaml"),s=e.includes("package-lock.json"),i=e.includes("yarn.lock"),d=e.includes("deno.json")||e.includes("deno.jsonc");if(!(s||o&&!t&&!i&&!d))return{};let p=P(n)?.scripts||{};return{...Object.entries(p).map(([f,u])=>[f,`npm run ${f}`]).reduce((f,[u,v])=>(f[u]=[v],f),{}),install:["npm install"],outdated:["npm outdated"]}}}),de=rn});var cn,fe,ue=a(()=>{"use strict";O();x();cn=y({name:"pnpm",actions:async n=>{if(!n.rootFiles.includes("pnpm-lock.yaml"))return{};let s=P(n)?.scripts||{},i=n.rootFiles.includes("pnpm-workspace.yaml");return{...Object.entries(s).map(([r,g])=>[r,`pnpm run ${r}`]).reduce((r,[g,p])=>(r[g]=[p],r),{}),install:["pnpm install"],outdated:[i?"pnpm outdated -r":"pnpm outdated"]}}}),fe=cn});var K,an,he,ye=a(()=>{"use strict";K=D(require("fs"),1);x();an=y({name:"ruby",actions:async n=>{let e=K.default.readdirSync(n.path),o=e.includes("Gemfile"),t=e.includes("Rakefile"),s=e.includes("config.ru"),i=K.default.existsSync(`${n.path}/config/application.rb`);if(!(o||t))return{};let r={install:["bundle install"],update:["bundle update"],outdated:["bundle outdated"]};return i&&(r.dev=["bundle exec rails server"],r.repl=["bundle exec rails console"]),s&&!i&&(r.dev=["bundle exec rackup"]),r}}),he=an});var be,ln,ve,ke=a(()=>{"use strict";be=D(require("fs"),1);x();ln=y({name:"uv",actions:async n=>{let e=be.default.readdirSync(n.path),o=e.includes("pyproject.toml");return e.includes("uv.lock")||o?{install:["uv sync"]}:{}}}),ve=ln});var gn,De,Pe=a(()=>{"use strict";O();x();gn=y({name:"yarn",actions:async n=>{let e=n.rootFiles.includes("package.json"),o=n.rootFiles.includes("yarn.lock");if(!(e&&o))return{};let i=P(n)?.scripts||{};return{...Object.entries(i).map(([r,g])=>[r,`yarn run ${r}`]).reduce((r,[g,p])=>(r[g]=[p],r),{}),install:["yarn install"],outdated:["yarn outdated"]}}}),De=gn});var T,Q=a(()=>{"use strict";ge();me();ue();ye();ke();Pe();T={deno:le,npm:de,pnpm:fe,ruby:he,uv:ve,yarn:De}});var Ae,xe=a(()=>{Ae={name:"denvig",version:"0.3.0",license:"MIT",description:"A CLI tool to consistently manage cross-discipline projects",bin:{denvig:"./dist/cli.cjs"},type:"module",files:["dist/","LICENSE","README.md"],scripts:{build:"rm -rf dist && tsup","check-types":"tsc --noEmit",prepublishOnly:"npm run build",lint:"biome check","lint:fix":"biome check --fix",test:"node --test src/**/*.test.ts","test:ci":"node --test src/**/*.test.ts --reporter=default",dev:"tsc --watch"},dependencies:{minimist:"^1.2.8",yaml:"^2.4.5",zod:"^4.1.5"},devDependencies:{"@biomejs/biome":"^2.2.2","@types/minimist":"^1.2.5","@types/node":"^22",tsup:"^8.5.0",typescript:"^5.0.0"},engines:{node:">=22"},repository:{type:"git",url:"git+https://github.com/marcqualie/denvig.git"},keywords:["cli","node","developer-tools","productivity","typescript"]}});function S(){return Ae.version}var H=a(()=>{"use strict";xe()});var b,F=a(()=>{"use strict";b=class{name;description;usage;example;args;flags;handler;constructor(e){this.name=e.name,this.description=e.description||"",this.usage=e.usage,this.example=e.example,this.args=e.args,this.flags=e.flags,this.handler=e.handler}async run(e,o,t,s){try{return await this.handler({project:e,args:o,flags:t,extraArgs:s})}catch(i){return console.error(`Error executing command "${this.name}":`,i),{success:!1,message:"fail"}}}}});var Se={};w(Se,{runCommand:()=>dn});var Re,dn,Fe=a(()=>{"use strict";Re=require("child_process");F();H();dn=new b({name:"run",description:"Run an action from the project. If no action is specified, lists available actions.",usage:"run [action]",example:"run build",args:[{name:"action",description:"The action to run (e.g. build, test, deploy)",required:!1,type:"string"}],flags:[],handler:async({project:n,args:e,extraArgs:o=[]})=>{let t=await n.actions;if(!e.action){console.log(`Denvig v${S()}`),console.log(""),console.log("Usage: denvig run [action] [...actionArgs]"),console.log(""),console.log("Available actions:");for(let d in t){if(!t[d])continue;let r=t[d];for(let g of r){let p=g.split(`
3
+ `),m=p[0],f=p.slice(1);console.log(` ${d}: ${m}`);for(let u of f)u.trim()&&console.log(`${" ".repeat(d.length+4)}${u}`)}}return{success:!0,message:"No action specified."}}let s=t[e.action];if(!s)return console.error(`Action "${e.action}" not found in project ${n.name}.`),{success:!1,message:`Action "${e.action}" not found.`};let i={success:!0};for(let d of s){let r=`${d} ${o.join(" ")}`.trim();console.log(`$ ${r}`);let g={...process.env,DENVIG_PROJECT:n.slug},p=process.stdout.isTTY&&process.stdin.isTTY,m,f;p?process.platform==="darwin"?(m="script",f=["-q","/dev/null","sh","-c",r]):(m="script",f=["-q","-c",r,"/dev/null"]):(m="sh",f=["-c",r]);let u=(0,Re.spawn)(m,f,{cwd:n.path,env:g,stdio:"inherit"}),v=await new Promise(k=>{u.on("close",I=>{k({success:I===0})})});v.success||(i=v)}return i}})});var M,we=a(()=>{"use strict";M=n=>n.replace(process.env.HOME||"/root","~")});var Je={};w(Je,{configCommand:()=>mn});var Ee,Oe,mn,Le=a(()=>{"use strict";Ee=require("yaml");F();G();we();Oe=n=>{let e=Object.fromEntries(Object.entries({...n,$sources:void 0}).filter(([o,t])=>t!==void 0));(0,Ee.stringify)(e,{indent:2,lineWidth:80}).trim().split(`
4
+ `).map(o=>console.log(` ${M(o)}`))},mn=new b({name:"config",description:"Display the current global and project configuration.",usage:"config",example:"config",args:[],flags:[],handler:({project:n})=>{let e=$(),o=n.config;return console.log("Denvig Config"),console.log(""),console.log(`Global: ${e.$sources.map(t=>M(t)).join(", ")||"default"}`),Oe(e),console.log(""),console.log(`Project: ${n.config.$sources.map(t=>M(t)).join(", ")||"default"}`),console.log(` slug: ${n.slug}`),Oe(o),{success:!0,message:"Configuration displayed."}}})});var Ne={};w(Ne,{pluginsCommand:()=>fn});var fn,Ge=a(()=>{"use strict";F();Q();fn=new b({name:"plugins",description:"Show a list of available plugins and their actions",usage:"plugins",example:"denvig plugins",args:[],flags:[],handler:async({project:n})=>{for(let[e,o]of Object.entries(T)){let t=await o.actions(n),s=Object.keys(t);console.log(`${o.name}: ${s.length} actions`);for(let i of s)console.log(` - ${i}: ${t[i].join(" && ")}`)}return{success:!0}}})});var _e={};w(_e,{versionCommand:()=>un});var un,Te=a(()=>{"use strict";F();H();un=new b({name:"version",description:"Show the current version of Denvig",usage:"version",example:"denvig version",args:[],flags:[],handler:()=>(console.log(`v${S()}`),{success:!0})})});var qe={};w(qe,{infoCommand:()=>hn});var hn,He=a(()=>{"use strict";F();hn=new b({name:"info",description:"Show information about the current project",usage:"info",example:"denvig info",args:[],flags:[],handler:async({project:n})=>{let e=null;try{let s=`${n.path}/package.json`,i=await import("fs");if(i.existsSync(s)){let d=JSON.parse(i.readFileSync(s,"utf-8"));d.repository?.url&&(e=d.repository.url.replace("git+","").replace(".git",""))}}catch{}let o=await n.actions,t={name:n.name,primaryPackageManager:n.primaryPackageManager,allPackageManagers:n.packageManagers,numberOfActions:Object.keys(o).length,githubRepository:e};return console.log(`Project: ${t.name}`),console.log(`Primary Package Manager: ${t.primaryPackageManager||"None detected"}`),console.log(`All Package Managers: ${t.allPackageManagers.join(", ")||"None detected"}`),console.log(`Available Actions: ${t.numberOfActions}`),t.githubRepository&&console.log(`GitHub Repository: ${t.githubRepository}`),{success:!0}}})});var X=D(require("minimist"),1);G();var $e=D(require("fs"),1);Q();Y();var je=async n=>{let e={};n.config.actions&&(e={...Object.entries(n.config.actions).reduce((o,[t,s])=>(o[t]=[s.command],o),{})});for(let[o,t]of Object.entries(T)){let s=await t.actions(n);e=_(e,s)}return e};G();var C=require("fs"),A=require("zod"),eo=A.z.object({id:A.z.string().describe("Unique identifier for the ecosystem / dependency"),name:A.z.string().describe("Name of the dependency"),versions:A.z.array(A.z.string()).describe("List of versions available for the dependency"),ecosystem:A.z.string().describe("Ecosystem of the dependency (e.g., npm, rubygems, pip)")}),Ce=n=>{let e=[];if((0,C.existsSync)(`${n.path}/package.json`)){e.push({id:"npm:npm",name:"npm",ecosystem:"system",versions:[]});let o=JSON.parse((0,C.readFileSync)(`${n.path}/package.json`,"utf8"));if(o.dependencies)for(let[t,s]of Object.entries({...o.dependencies,...o.devDependencies}))e.push({id:`npm:${t}`,name:t,ecosystem:"npm",versions:Array.isArray(s)?s:[s]})}return(0,C.existsSync)(`${n.path}/yarn.lock`)&&e.push({id:"npm:yarn",name:"yarn",ecosystem:"system",versions:[]}),(0,C.existsSync)(`${n.path}/pnpm-lock.yaml`)&&e.push({id:"npm:pnpm",name:"pnpm",ecosystem:"system",versions:[]}),((0,C.existsSync)(`${n.path}/deno.json`)||(0,C.existsSync)(`${n.path}/deno.jsonc`))&&e.push({id:"deno:deno",name:"deno",ecosystem:"system",versions:[process.version]}),e};var q=class{slug;config;constructor(e){this.slug=e,this.config=ae(e)}get name(){return this.config.name}get path(){return`${$().codeRootDir}/${this.slug}`}get packageManagers(){let e=this.rootFiles,o=[];return(e.includes("pnpm-lock.yaml")||e.includes("package.json"))&&o.push("pnpm"),(e.includes("package-lock.json")||e.includes("package.json"))&&o.push("npm"),e.includes("yarn.lock")&&o.push("yarn"),(e.includes("deno.json")||e.includes("deno.jsonc"))&&o.push("deno"),e.includes("pyproject.toml")&&o.push("uv"),o}get primaryPackageManager(){return this.packageManagers[0]||null}get dependencies(){return Ce(this)}get actions(){return je(this)}get rootFiles(){return $e.default.readdirSync(this.path)}};H();var Me=[{name:"project",description:"The project slug to run against. Defaults to current directory.",required:!1,type:"string",defaultValue:void 0}];async function yn(){let n=process.argv[2],e=process.argv.slice(2),o=$(),t=process.cwd(),s=(0,X.default)(process.argv.slice(2)).project?.toString()||t.replace(`${o.codeRootDir}/`,"").split("/").slice(0,2).join("/"),i=new q(s),d=[...o.quickActions||[],...i?.config?.quickActions||[]].sort();d.includes(n)&&(e=["run",...process.argv.slice(2)],n="run",console.log("> Proxying to denvig run",...process.argv.slice(2)));let{runCommand:r}=await Promise.resolve().then(()=>(Fe(),Se)),{configCommand:g}=await Promise.resolve().then(()=>(Le(),Je)),{pluginsCommand:p}=await Promise.resolve().then(()=>(Ge(),Ne)),{versionCommand:m}=await Promise.resolve().then(()=>(Te(),_e)),{infoCommand:f}=await Promise.resolve().then(()=>(He(),qe)),u={run:r,config:g,plugins:p,version:m,info:f},v=u[n],k=(0,X.default)(e),I=v?.args.reduce((l,c,J)=>{let L=k._[J+1];return L!==void 0?l[c.name]=L:c.required&&(console.error(`Missing required argument: ${c.name}`),process.exit(1)),l},{})||{},Ie=k._.slice(v?.args.length+1).map(l=>String(l))||[],Z=[...Me,...v?.flags||[]],Ue=new Set(Z.map(l=>l.name)),Ve=Z.reduce((l,c)=>(k[c.name]!==void 0?l[c.name]=k[c.name]:c.defaultValue!==void 0?l[c.name]=c.defaultValue:c.required&&(console.error(`Missing required flag: ${c.name}`),process.exit(1)),l),{}),E=[];for(let[l,c]of Object.entries(k))l!=="_"&&!Ue.has(l)&&(c===!0?E.push(`--${l}`):c===!1?E.push(`--no-${l}`):E.push(`--${l}`,String(c)));let We=[...Ie,...E];if(!n){console.log(`Denvig v${S()}`),console.log(""),console.log("Usage: denvig <command> [args] [flags]"),console.log(""),console.log("Available commands:"),Object.keys(u).forEach(c=>{console.log(` - ${u[c].usage.padEnd(20," ")} ${u[c].description}`)}),console.log(""),console.log("Quick Actions:");for(let c of d){let J=(await i?.actions)?.[c];if(!J){console.log(` - ${c.padEnd(20," ")} not defined`);return}for(let L of J){let ee=L.split(`
5
+ `),ze=ee[0],Ye=ee.slice(1);console.log(` - ${c.padEnd(20," ")} $ ${ze}`);for(let ne of Ye)ne.trim()&&console.log(`${" ".repeat(27)}${ne}`)}}console.log(""),console.log("Global flags:"),Me.forEach(c=>{console.log(` --${c.name.padEnd(20," ")} ${c.description}`)}),process.exit(1)}u[n]||(console.error(`Command "${n}" not found.`),process.exit(1));try{s||console.error("No project provided or detected.");let{success:l}=await v.run(i,I,Ve,We);l||process.exit(1)}catch(l){console.error(`Error executing command "${n}":`,l),process.exit(1)}}yn();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "denvig",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "description": "A CLI tool to consistently manage cross-discipline projects",
6
6
  "bin": {
@@ -25,10 +25,10 @@
25
25
  "dependencies": {
26
26
  "minimist": "^1.2.8",
27
27
  "yaml": "^2.4.5",
28
- "zod": "^4.0.14"
28
+ "zod": "^4.1.5"
29
29
  },
30
30
  "devDependencies": {
31
- "@biomejs/biome": "^2.1.3",
31
+ "@biomejs/biome": "^2.2.2",
32
32
  "@types/minimist": "^1.2.5",
33
33
  "@types/node": "^22",
34
34
  "tsup": "^8.5.0",