denvig 0.1.2 → 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
 
@@ -16,12 +19,6 @@ You can install the CLI tool globally using npm:
16
19
  npm install -g denvig
17
20
  ```
18
21
 
19
-
20
- ### Binary
21
-
22
- Prebuilt binaries can be downloaded from the [releases page](https://github.com/marcqualie/denvig/releases).
23
-
24
-
25
22
  After installation, the `denvig` command will be available in your terminal.
26
23
 
27
24
 
@@ -29,10 +26,10 @@ After installation, the `denvig` command will be available in your terminal.
29
26
  ## Commands
30
27
 
31
28
 
32
- ### Run
29
+ ### Actions
33
30
 
34
- Execites an action inside the project. Defaults are detected for common languages/frameworks, but you can also
35
- specify your own actions in the `denvig.yml` file.
31
+ Executes an action inside the project. Defaults are detected for common languages/frameworks, but you can also
32
+ specify your own actions in the `.denvig.yml` file.
36
33
 
37
34
  ```shell
38
35
  denvig run build
@@ -41,7 +38,7 @@ denvig run test
41
38
  denvig run dev
42
39
  ```
43
40
 
44
- Some commands are common to many frameworks so they have root aliases for convenience:
41
+ Some actions are common to many frameworks so they have quick access for convenience:
45
42
 
46
43
  ```shell
47
44
  denvig build
@@ -58,10 +55,14 @@ denvig outdated
58
55
  There is a set of core languages and frameworks that Denvig will support out of the box. Any language or framework
59
56
  can be supported by using the per project configs.
60
57
 
61
- - [ ] Deno
62
- - [ ] Node.js / NextJS / Vite
63
- - [ ] Ruby / Rails
64
- - [ ] Python / Pip
58
+ - [x] Node.js (npm, pnpm, yarn)
59
+ - [ ] Bun
60
+ - [ ] Vite
61
+ - [x] Deno
62
+ - [ ] NextJS
63
+ - [ ] Ruby
64
+ - [ ] Rails
65
+ - [x] Python
65
66
 
66
67
 
67
68
 
package/dist/cli.cjs ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
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,25 +1,40 @@
1
1
  {
2
2
  "name": "denvig",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "description": "A CLI tool to consistently manage cross-discipline projects",
6
6
  "bin": {
7
- "denvig": "./dist/denvig"
7
+ "denvig": "./dist/cli.cjs"
8
8
  },
9
+ "type": "module",
9
10
  "files": [
10
- "dist/denvig",
11
+ "dist/",
11
12
  "LICENSE",
12
13
  "README.md"
13
14
  ],
14
15
  "scripts": {
15
- "build": "deno task build",
16
- "prepublishOnly": "npm run build"
16
+ "build": "rm -rf dist && tsup",
17
+ "check-types": "tsc --noEmit",
18
+ "prepublishOnly": "npm run build",
19
+ "lint": "biome check",
20
+ "lint:fix": "biome check --fix",
21
+ "test": "node --test src/**/*.test.ts",
22
+ "test:ci": "node --test src/**/*.test.ts --reporter=default",
23
+ "dev": "tsc --watch"
17
24
  },
18
25
  "dependencies": {
19
- "zod": "^4.0.14"
26
+ "minimist": "^1.2.8",
27
+ "yaml": "^2.4.5",
28
+ "zod": "^4.1.5"
29
+ },
30
+ "devDependencies": {
31
+ "@biomejs/biome": "^2.2.2",
32
+ "@types/minimist": "^1.2.5",
33
+ "@types/node": "^22",
34
+ "tsup": "^8.5.0",
35
+ "typescript": "^5.0.0"
20
36
  },
21
37
  "engines": {
22
- "deno": ">=2.4",
23
38
  "node": ">=22"
24
39
  },
25
40
  "repository": {
@@ -28,7 +43,7 @@
28
43
  },
29
44
  "keywords": [
30
45
  "cli",
31
- "deno",
46
+ "node",
32
47
  "developer-tools",
33
48
  "productivity",
34
49
  "typescript"
package/dist/denvig DELETED
Binary file
File without changes