@denvig/sdk 0.7.0-alpha.4
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/LICENSE +8 -0
- package/README.md +17 -0
- package/dist/chunk-CMqjfN_6.cjs +1 -0
- package/dist/fs.cjs +1 -0
- package/dist/fs.d.ts +15 -0
- package/dist/fs.js +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +273 -0
- package/dist/index.js +1 -0
- package/dist/internal.cjs +1 -0
- package/dist/internal.d.ts +202 -0
- package/dist/internal.js +1 -0
- package/dist/path-DElA4WIM.js +1 -0
- package/dist/path-pt0IDc1N.cjs +1 -0
- package/dist/project-BA4nj7bB.js +1 -0
- package/dist/project-BqMRVXi0.cjs +1 -0
- package/dist/project-DmYu4L1C.d.ts +247 -0
- package/dist/reconcile-C90QGHEJ.d.ts +50 -0
- package/dist/reconcile-CvY7dT3H.js +1 -0
- package/dist/reconcile-DU2Wb6SO.cjs +1 -0
- package/dist/safeReadFile-BlLUgHuA.cjs +1 -0
- package/dist/safeReadFile-Z2PHqO9j.js +1 -0
- package/dist/semver-CxqsdmU_.cjs +1 -0
- package/dist/semver-dZSpezIR.js +1 -0
- package/dist/teardown-BuHyVdhH.d.ts +764 -0
- package/dist/teardown-DgjT-aE7.js +208 -0
- package/dist/teardown-DypXa0Wy.cjs +208 -0
- package/dist/testing.cjs +1 -0
- package/dist/testing.d.ts +32 -0
- package/dist/testing.js +1 -0
- package/dist/utils.cjs +1 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.js +1 -0
- package/package.json +109 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
const e=require("./chunk-CMqjfN_6.cjs"),t=require("./safeReadFile-BlLUgHuA.cjs");let n=require("node:child_process"),r=require("node:fs/promises"),i=require("node:os"),a=require("node:path");a=e.t(a,1);let o=require("yaml"),s=require("semver"),c=require("node:util"),l=require("node:crypto"),u=require("node:fs"),d=require("zod"),f=require("node:net");const p=()=>process.env.DENVIG_CLI_LOGS_ENABLED!==`0`,m=()=>process.env.DENVIG_CLI_LOGS_PATH?(0,a.resolve)(process.env.DENVIG_CLI_LOGS_PATH):(0,a.resolve)((0,i.homedir)(),`.denvig`,`logs`,`cli.jsonl`),h=async()=>{await(0,r.mkdir)((0,a.resolve)(m(),`..`),{recursive:!0})},g=async e=>{if(p())try{await h(),await(0,r.appendFile)(m(),`${JSON.stringify(e)}\n`,`utf-8`)}catch{}},_=e=>{let t=Date.now();return{finish:async(n,r)=>{let i={timestamp:new Date().toISOString(),version:e.version,slug:void 0,command:e.command,via:void 0,duration:Date.now()-t,path:e.path,status:n,error:void 0};e.slug!==void 0&&(i.slug=e.slug),e.via!==void 0&&(i.via=e.via),r!==void 0&&(i.error=r),await g(i)}}},v=(e,t)=>{for(let[n,r]of Object.entries(t))e[n]||(e[n]=[]),e[n].push(...r);return e},y=[`pnpm-lock.yaml:`,`yarn.lock:`,`Gemfile.lock:`,`uv.lock:`,`deno.lock:`],b=e=>{for(let t of y)if(e.startsWith(t)){let n=e.slice(t.length).match(/^((?:@[^@/]+\/)?[^@]+)@([^(@]+)/);if(n)return{name:n[1],version:n[2]}}return null},x=e=>y.some(t=>e.startsWith(t)),ee=(e,t)=>{if(t<=0)return e.filter(e=>e.versions.some(e=>e.source.includes(`#dependencies`)||e.source.includes(`#devDependencies`)));let n=new Map;for(let t of e)for(let e of t.versions){let r=b(e.source);if(!r)continue;let i=`${r.name}@${r.version}`,a=n.get(i)??new Set;a.add(t.name),n.set(i,a)}let r=new Set,i=[];for(let t of e)for(let e of t.versions)(e.source.includes(`#dependencies`)||e.source.includes(`#devDependencies`))&&(r.has(t.name)||r.add(t.name),i.push({name:t.name,version:e.resolved,depth:0}));let a=new Set;for(;i.length>0;){let o=i.shift();if(!o)break;if(o.depth>=t)continue;let s=`${o.name}@${o.version}`;if(a.has(s))continue;a.add(s);let c=n.get(s);if(c)for(let t of c){r.add(t);let n=e.find(e=>e.name===t);if(n)for(let e of n.versions){let t=b(e.source);t?.name===o.name&&t.version===o.version&&i.push({name:n.name,version:e.resolved,depth:o.depth+1})}}}return e.filter(e=>r.has(e.name))},te=e=>e.endsWith(`#dependencies`),ne=e=>e.endsWith(`#devDependencies`),re=(e,t,n)=>{let r=new Map;for(let t of e)r.set(t.name,t);let i=[],a=new Set;for(let t of e)if(!(n&&t.ecosystem!==n)){for(let e of t.versions)if(!x(e.source)){let n=ne(e.source);if(te(e.source)||n){let r=`${t.name}@${e.resolved}`;a.has(r)||(a.add(r),i.push({dep:t,version:e.resolved,isDevDependency:n,children:[]}))}}}if(t>0){let r=new Map;for(let t of e)if(!(n&&t.ecosystem!==n))for(let e of t.versions){let n=b(e.source);if(n){let e=`${n.name}@${n.version}`,i=r.get(e)||[];i.some(e=>e.name===t.name)||(i.push(t),r.set(e,i))}}let a=(e,n,i)=>{if(n>=t)return;let o=`${e.dep.name}@${e.version}`;if(i.has(o))return;i.add(o);let s=r.get(o)||[];for(let t of s){let r=t.versions.find(t=>{let n=b(t.source);return n?.name===e.dep.name&&n?.version===e.version});if(r){let o={dep:t,version:r.resolved,isDevDependency:!1,children:[]};e.children.push(o),a(o,n+1,new Set(i))}}e.children.sort((e,t)=>e.dep.name.localeCompare(t.dep.name))};for(let e of i)a(e,0,new Set)}i.sort((e,t)=>{let n=e.dep.ecosystem.localeCompare(t.dep.ecosystem);return n===0?e.dep.name.localeCompare(t.dep.name):n});let o=[],s=(e,t,n,r)=>{o.push({name:e.dep.name,version:e.version,ecosystem:e.dep.ecosystem,isDevDependency:e.isDevDependency,depth:t,isLast:n,hasChildren:e.children.length>0,parentPath:[...r]});let i=[...r,n];e.children.forEach((n,r)=>{s(n,t+1,r===e.children.length-1,i)})};return i.forEach((e,t)=>{s(e,0,t===i.length-1,[])}),o},ie=(e,t,n,r)=>{if(!x(n))return{name:e,version:t,children:[]};let i=[{name:e,version:t}],a=n,o=0;for(;o<50;){let e=b(a);if(!e)break;i.unshift({name:e.name,version:e.version});let t=r.get(e.name);if(!t)break;let n=t.versions.find(t=>t.resolved===e.version);if(!n||!x(n.source))break;a=n.source,o++}if(i.length===0)return null;let s={name:i[0].name,version:i[0].version,children:[]},c=s;for(let e=1;e<i.length;e++){let t={name:i[e].name,version:i[e].version,children:[]};c.children.push(t),c=t}return s},ae=async()=>{let e=`${(0,i.homedir)()}/.cache/denvig/dependencies/npm`;return await(0,r.mkdir)(e,{recursive:!0}),e},oe=e=>{let t=e.replace(/@/g,`_at_`).replace(/\//g,`__`);return t=t.replace(/[^a-zA-Z0-9\-_.]/g,`_`),t=t.replace(/\.{2,}/g,`_`),t=t.replace(/^\.+/,`_`),t.length===0&&(t=`_empty_`),t.length>200&&(t=t.slice(0,200)),t},se=async e=>{let t=oe(e);return`${await ae()}/${t}.json`},ce=async e=>{try{let t=await(0,r.stat)(e);return Date.now()-t.mtimeMs<36e5}catch{return!1}},le=async e=>{let t=await se(e);if(!await ce(t))return null;try{let e=await(0,r.readFile)(t,`utf-8`),n=JSON.parse(e);return n.versionDates?n:null}catch{return null}},ue=async(e,t)=>{try{await(0,r.writeFile)(await se(e),JSON.stringify(t),`utf-8`)}catch{}},de=async(e,t=!1)=>{if(!t){let t=await le(e);if(t)return t}try{let t=await fetch(`https://registry.npmjs.com/${encodeURIComponent(e)}`,{headers:{Accept:`application/json`}});if(!t.ok)return null;let n=await t.json(),r=Object.keys(n.versions),i=n[`dist-tags`]?.latest||r[r.length-1],a={};if(n.time)for(let[e,t]of Object.entries(n.time))e!==`created`&&e!==`modified`&&(a[e]=t);let o={versions:r,latest:i,versionDates:a};return await ue(e,o),o}catch{return null}},S=e=>{let t=e.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);return t?{major:Number.parseInt(t[1],10),minor:Number.parseInt(t[2],10),patch:Number.parseInt(t[3],10),prerelease:t[4]||``}:null},C=(e,t)=>{let n=S(e),r=S(t);return!n||!r?0:n.major===r.major?n.minor===r.minor?n.patch===r.patch?n.prerelease&&!r.prerelease?-1:!n.prerelease&&r.prerelease?1:0:n.patch-r.patch:n.minor-r.minor:n.major-r.major},fe=(e,t)=>{let n=S(e);if(!n||n.prerelease)return!1;if(t.startsWith(`^`)){let r=S(t.slice(1));return r?r.major===0?n.major===0&&n.minor===r.minor&&n.patch>=r.patch:n.major===r.major&&C(e,t.slice(1))>=0:!1}if(t.startsWith(`~`)){let e=S(t.slice(1));return e?n.major===e.major&&n.minor===e.minor&&n.patch>=e.patch:!1}if(t.startsWith(`>=`))return C(e,t.slice(2))>=0;if(t.startsWith(`>`)&&!t.startsWith(`>=`))return C(e,t.slice(1))>0;let r=S(t);return r?n.major===r.major&&n.minor===r.minor&&n.patch===r.patch:!1},pe=(e,t)=>{let n=e.filter(e=>fe(e,t)).sort(C);return n.length>0?n[n.length-1]:null},me=e=>{if(e.versions.length===0)return null;let t=e.versions[0],n=t.source.includes(`#devDependencies`),r=e.versions.find(e=>!e.specifier.startsWith(`catalog:`))?.specifier??t.specifier;return{current:t.resolved,specifier:r,isDevDependency:n}},he=async(e,t={})=>{let n=t.cache??!0,r=t.depth??0,i=[],a=ee(e,r).map(async e=>{let t=me(e);if(!t)return;let r=await de(e.name,!n);if(!r)return;let a=pe(r.versions,t.specifier),o=r.latest,s=a&&a!==t.current,c=o&&o!==t.current;if(s||c){let n=a||t.current;i.push({...e,wanted:n,latest:o,specifier:t.specifier,isDevDependency:t.isDevDependency,currentDate:r.versionDates?.[t.current],wantedDate:r.versionDates?.[n],latestDate:r.versionDates?.[o]})}});return await Promise.all(a),i},ge=async()=>{let e=`${(0,i.homedir)()}/.cache/denvig/dependencies/jsr`;return await(0,r.mkdir)(e,{recursive:!0}),e},_e=async e=>{let t=oe(e);return`${await ge()}/${t}.json`},ve=async e=>{try{let t=await(0,r.stat)(e);return Date.now()-t.mtimeMs<36e5}catch{return!1}},ye=async e=>{let t=await _e(e);if(!await ve(t))return null;try{let e=await(0,r.readFile)(t,`utf-8`);return JSON.parse(e)}catch{return null}},be=async(e,t)=>{try{await(0,r.writeFile)(await _e(e),JSON.stringify(t),`utf-8`)}catch{}},xe=async(e,t=!1)=>{if(!t){let t=await ye(e);if(t)return t}try{let t=await fetch(`https://jsr.io/${e}/meta.json`,{headers:{Accept:`application/json`}});if(!t.ok)return null;let n=await t.json(),r=Object.entries(n.versions).filter(([e,t])=>!t.yanked).map(([e])=>e),i=n.latest,a={};for(let[e,t]of Object.entries(n.versions))t.createdAt&&(a[e]=t.createdAt);let o={versions:r,latest:i,versionDates:Object.keys(a).length>0?a:void 0};return await be(e,o),o}catch{return null}},Se=async(e,t={})=>{let n=t.cache??!0,r=t.depth??0,i=[],a=ee(e,r).map(async e=>{let t=me(e);if(!t)return;let r=await xe(e.name,!n);if(!r)return;let a=t.specifier===`*`?r.latest:pe(r.versions,t.specifier),o=r.latest,s=a&&a!==t.current,c=o&&o!==t.current;if(s||c){let n=a||t.current;i.push({...e,wanted:n,latest:o,specifier:t.specifier,isDevDependency:t.isDevDependency,currentDate:r.versionDates?.[t.current],wantedDate:r.versionDates?.[n],latestDate:r.versionDates?.[o]})}});return await Promise.all(a),i},w=async e=>{let t=`${e.path}/package.json`;try{let e=await(0,r.readFile)(t,`utf-8`);return JSON.parse(e)}catch{return null}},T=e=>e,Ce=new Map,we=e=>{let t=e.match(/^(npm|jsr):(.+)@([^@]+)$/);return t?{ecosystem:t[1],name:t[2],versionRange:t[3]}:null},Te=(e,t)=>{for(let[n,r]of Object.entries(t))if(n===e||n.startsWith(`${e}@`))return{specKey:n,resolved:r};return null},Ee=(e,t)=>{for(let n of Object.keys(t)){let t=n.lastIndexOf(`@`);if(!(t<=0)&&n.slice(0,t)===e)return n.slice(t+1)}return null},De=async e=>{try{let t=await(0,r.readFile)(e,`utf-8`);return JSON.parse(t)}catch{return{}}},Oe=T({name:`deno`,actions:async e=>{let n=e.rootFiles;if(!(n.includes(`deno.json`)||n.includes(`deno.jsonc`)))return{};let r=(await w(e))?.scripts||{},i={...Object.entries(r).map(([e,t])=>[e,`deno ${t}`]).reduce((e,[t,n])=>(e[t]=[n],e),{}),install:[`deno install`],outdated:[`deno outdated`]},a=await t.n(`${e.path}/deno.json`)?`${e.path}/deno.json`:await t.n(`${e.path}/deno.jsonc`)?`${e.path}/deno.jsonc`:null,o=(a?await De(a):{}).tasks||{};return i=v(i,{test:[o?.test?`deno task test`:`deno test`],lint:[o?.lint?`deno task lint`:`deno lint`],"check-types":[o?.checkTypes?`deno task check-types`:`deno check`],...Object.entries(o).reduce((e,[t,n])=>(e[t]=[n.startsWith(`deno`)?n:`deno task ${t}`],e),{}),install:[`deno install`],outdated:[`deno outdated`]}),i},dependencies:async e=>{if(!await t.n(`${e.path}/deno.lock`))return[];let n=Ce.get(e.path);if(n)return n;let i=new Map,a=new Set,o=(e,t,n,r,a,o)=>{let s=i.get(e);s?s.versions.push({resolved:r,specifier:o,source:a}):i.set(e,{id:e,name:t,ecosystem:n,versions:[{resolved:r,specifier:o,source:a}]})},s=await(0,r.readFile)(`${e.path}/deno.lock`,`utf-8`),c=JSON.parse(s),l=c.workspace?.dependencies||[];for(let e of l){let t=c.specifiers[e];if(!t)continue;let n=we(e);if(!n)continue;let r=`${n.ecosystem}:${n.name}`;a.add(r),o(r,n.name,n.ecosystem,t,`.#dependencies`,n.versionRange)}if(c.jsr){for(let[e,t]of Object.entries(c.jsr))if(t.dependencies)for(let n of t.dependencies){let t=Te(n,c.specifiers);if(!t)continue;let r=we(t.specKey);if(!r)continue;let i=`${r.ecosystem}:${r.name}`;a.has(i)||o(i,r.name,r.ecosystem,t.resolved,`deno.lock:${e}`,t.resolved)}}if(c.npm)for(let[e,t]of Object.entries(c.npm)){let n=[...t.dependencies||[],...t.optionalDependencies||[]];if(n.length!==0)for(let t of n){let n=`npm:${t}`;if(a.has(n))continue;let r=Ee(t,c.npm);r&&o(n,t,`npm`,r,`deno.lock:${e}`,r)}}let u=Array.from(i.values()).sort((e,t)=>e.name.localeCompare(t.name));return Ce.set(e.path,u),u},outdatedDependencies:async(e,n)=>{if(!await t.n(`${e.path}/deno.lock`))return[];let r=await Oe.dependencies?.(e);if(!r)return[];let i=r.filter(e=>e.ecosystem===`npm`),a=r.filter(e=>e.ecosystem===`jsr`),[o,s]=await Promise.all([he(i,n),Se(a,n)]);return[...o,...s]}}),ke=T({name:`npm`,actions:async e=>{let t=e.rootFiles,n=t.includes(`package.json`),r=t.includes(`package-lock.json`);if(!(n&&r))return{};let i=(await w(e))?.scripts||{};return{...Object.entries(i).map(([e,t])=>[e,`npm run ${e}`]).reduce((e,[t,n])=>(e[t]=[n],e),{}),install:[`npm install`],outdated:[`npm outdated`]}}}),Ae=e=>{let t=0,n=0,r={},i=[];for(let[a,o]of Object.entries(e.dependencies)){let e=Object.keys(o.versions),s=Object.keys(o.optimisedVersions||{});t+=e.length,n+=s.length,e.length!==s.length&&(r[a]=e.filter(e=>!s.includes(e)),i.push({name:a,versions:e,optimisedVersions:s}))}return{totalDependencies:t,optimisedDependencies:n,removals:r,details:i}},je=async(e,t,i)=>{await(0,r.writeFile)(e,t,`utf-8`),await new Promise((t,r)=>{(0,n.spawn)(i,[`install`],{cwd:(0,a.dirname)(e),stdio:`inherit`,shell:!0}).on(`close`,e=>{e===0?t():r(Error(`${i} install failed with code ${e}`))})})},Me=(e,t)=>{let n=`0.0.0`;for(let r of t)(0,s.satisfies)(r,e)&&(n=r);return n===`0.0.0`?t[t.length-1]:n},Ne=e=>{let t=Object.keys(e),n=Object.values(e).flat(),r={};for(let e of n){let n=Me(e,t);r[n]||(r[n]=[]),r[n].push(e)}return r},Pe=e=>{let t=e.match(/^([^(]+)/);return t?t[1]:e},Fe=e=>{let t={},n=(0,o.parse)(e);if(!n.importers)return{dependencies:t};for(let[e,r]of Object.entries(n.importers)){let e=[r.dependencies,r.devDependencies,r.optionalDependencies];for(let n of e)if(n)for(let[e,r]of Object.entries(n)){let{specifier:n,version:i}=r;if(i.startsWith(`link:`))continue;let a=Pe(i);t[e]||(t[e]={versions:{}}),t[e].versions[a]||(t[e].versions[a]=[]),t[e].versions[a].includes(n)||t[e].versions[a].push(n),t[e].versions[a]=t[e].versions[a].sort((e,t)=>e.localeCompare(t,void 0,{numeric:!0})),t[e].versions=Object.fromEntries(Object.entries(t[e].versions).sort((e,t)=>e[0].localeCompare(t[0],void 0,{numeric:!0})))}}for(let[e,n]of Object.entries(t))t[e].optimisedVersions=Ne(n.versions);return{dependencies:t}},Ie=e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`),Le=e=>{let t=e.match(/^([^(]+)/);return t?t[1]:e},Re=(e,t)=>{for(let[n,r]of Object.entries(t))if(r.includes(e))return n;return null},ze=(e,t)=>{let n=Ie(t),r=RegExp(`^ '?${n}'?:.*\\n(?: .*\\n)*\\n?`,`gm`);return e.replace(r,``)},Be=(e,t,n)=>{let r=(0,o.parse)(e),i=e,a={};if(r.importers&&n)for(let e of Object.values(r.importers)){let r=[e.dependencies,e.devDependencies,e.optionalDependencies];for(let e of r)if(e)for(let[r,i]of Object.entries(e)){let e=i.version,{specifier:o}=i;if(e.startsWith(`link:`))continue;let s=Le(e);if(t[r]?.includes(s)){let t=n[r];if(t){let n=Re(o,t);n&&n!==s&&(a[e]=e.includes(`(`)?e.replace(/^[^(]+/,n):n)}}}}for(let[e,t]of Object.entries(a)){let n=RegExp(`^(\\s+version: )${Ie(e)}$`,`gm`);i=i.replace(n,`$1${t}`)}for(let[e,n]of Object.entries(t))for(let t of n){let n=`${e}@${t}`;i=ze(i,n),i=ze(i,n)}return i},Ve=e=>{if(/^\d+$/.test(e))return Number.parseInt(e,10)*60*1e3;let t=e.match(/^(\d+)(s|m|h|d|w)$/);if(!t)return null;let n=Number.parseInt(t[1],10);switch(t[2]){case`s`:return n*1e3;case`m`:return n*60*1e3;case`h`:return n*60*60*1e3;case`d`:return n*24*60*60*1e3;case`w`:return n*7*24*60*60*1e3;default:return null}},He=async e=>{try{return(0,o.parse)(await(0,r.readFile)(`${e}/pnpm-workspace.yaml`,`utf-8`))}catch{return null}},Ue=async e=>{let t=await He(e);if(!t)return null;let n=t.catalog&&typeof t.catalog==`object`?t.catalog:null,r=t.catalogs&&typeof t.catalogs==`object`?t.catalogs:null;return!n&&!r?null:{default:n??{},named:r??{}}},We=(e,t,n)=>{if(!e||!n.startsWith(`catalog:`))return null;let r=n.slice(8).trim(),i=r===``||r==="default"?`default`:r,a=i==="default"?e.default:e.named[i];if(!a)return null;let o=a[t];return o?{specifier:o,catalogName:i}:null},Ge=e=>e==="default"?`pnpm-workspace.yaml$catalog`:`pnpm-workspace.yaml$catalogs.${e}`,Ke=async e=>{try{let t=(0,o.parse)(await(0,r.readFile)(`${e}/pnpm-workspace.yaml`,`utf-8`));if(t?.minimumReleaseAge==null)return null;let n=Ve(String(t.minimumReleaseAge));return n===null?null:{minimumReleaseAgeMs:n,exclude:t.minimumReleaseAgeExclude??[]}}catch{return null}},qe=new Map,Je=e=>{let t=e.indexOf(`(`);return t===-1?e:e.slice(0,t)},Ye=e=>{if(/^\d/.test(e))return null;let t=e.match(/^((?:@[^@/]+\/)?[^@]+)@(.+)$/);return t?{name:t[1],version:t[2]}:null},Xe=T({name:`pnpm`,actions:async e=>{if(!e.rootFiles.includes(`pnpm-lock.yaml`))return{};let t=(await w(e))?.scripts||{},n=e.rootFiles.includes(`pnpm-workspace.yaml`);return{...Object.entries(t).map(([e,t])=>[e,`pnpm --reporter=silent run ${e}`]).reduce((e,[t,n])=>(e[t]=[n],e),{}),install:[`pnpm install`],outdated:[n?`pnpm outdated -r`:`pnpm outdated`]}},dependencies:async e=>{if(!await t.n(`${e.path}/pnpm-lock.yaml`))return[];let n=qe.get(e.path);if(n)return n;let i=new Map,a=(e,t,n,r,a,o)=>{let s=i.get(e);s?s.versions.push({resolved:r,specifier:o,source:a}):i.set(e,{id:e,name:t,ecosystem:n,versions:[{resolved:r,specifier:o,source:a}]})};i.set(`npm:pnpm`,{id:`npm:pnpm`,name:`pnpm`,ecosystem:`system`,versions:[]});let s=(0,o.parse)(await(0,r.readFile)(`${e.path}/pnpm-lock.yaml`,`utf-8`)),c=await Ue(e.path),l=new Set,u=(e,t,n)=>{let r=`npm:${e}`,i=Je(t.version),o=We(c,e,t.specifier);if(a(r,e,`npm`,i,n,t.specifier),o){let t=Ge(o.catalogName),n=`${r}@${t}`;l.has(n)||(l.add(n),a(r,e,`npm`,i,t,o.specifier))}};if(s?.importers)for(let[e,t]of Object.entries(s.importers)){let n=e===`.`?`.`:e;if(t.dependencies)for(let[e,r]of Object.entries(t.dependencies))r?.specifier&&r?.version&&u(e,r,`${n}#dependencies`);if(t.devDependencies)for(let[e,r]of Object.entries(t.devDependencies))r?.specifier&&r?.version&&u(e,r,`${n}#devDependencies`)}if(s?.snapshots)for(let[e,t]of Object.entries(s.snapshots)){let n={...t.dependencies};for(let[t,r]of Object.entries(n)){let n=Ye(r),i=n?n.name:t,o=Je(n?n.version:r),s=`pnpm-lock.yaml:${e}`;a(`npm:${i}`,i,`npm`,o,s,o)}}let d=Array.from(i.values()).sort((e,t)=>e.name.localeCompare(t.name));return qe.set(e.path,d),d},outdatedDependencies:async(e,n)=>{if(!await t.n(`${e.path}/pnpm-lock.yaml`))return[];let r=await Xe.dependencies?.(e);return r?he(r,n):[]},deduplicateDependencies:async(e,n)=>{let i=`${e.path}/pnpm-lock.yaml`;if(!await t.n(i))return null;let a=await(0,r.readFile)(i,`utf-8`),o=Fe(a),s=Ae(o),c=n?.dryRun??!1,l=!1;if(!c&&Object.keys(s.removals).length>0){let e={};for(let[t,n]of Object.entries(o.dependencies))s.removals[t]&&n.optimisedVersions&&(e[t]=n.optimisedVersions);await je(i,Be(a,s.removals,e),`pnpm`),l=!0}return{ecosystem:`pnpm-lock.yaml`,...s,applied:l}}}),Ze=async()=>{let e=`${(0,i.homedir)()}/.cache/denvig/dependencies/rubygems`;return await(0,r.mkdir)(e,{recursive:!0}),e},Qe=e=>{let t=e.replace(/[^a-zA-Z0-9\-_.]/g,`_`);return t=t.replace(/\.{2,}/g,`_`),t=t.replace(/^\.+/,`_`),t.length===0&&(t=`_empty_`),t.length>200&&(t=t.slice(0,200)),t},$e=async e=>{let t=Qe(e);return`${await Ze()}/${t}.json`},et=async e=>{try{let t=await(0,r.stat)(e);return Date.now()-t.mtimeMs<36e5}catch{return!1}},tt=async e=>{let t=await $e(e);if(!await et(t))return null;try{let e=await(0,r.readFile)(t,`utf-8`),n=JSON.parse(e);return n.versionDates?n:null}catch{return null}},nt=async(e,t)=>{try{await(0,r.writeFile)(await $e(e),JSON.stringify(t),`utf-8`)}catch{}},rt=async(e,t=!1)=>{if(!t){let t=await tt(e);if(t)return t}try{let t=await fetch(`https://rubygems.org/api/v1/versions/${encodeURIComponent(e)}.json`,{headers:{Accept:`application/json`}});if(!t.ok)return null;let n=await t.json(),r=n.map(e=>e.number),i=n.filter(e=>!e.prerelease).map(e=>e.number)[0]||r[0],a={};for(let e of n)e.created_at&&(a[e.number]=e.created_at);let o={versions:r,latest:i,versionDates:a};return await nt(e,o),o}catch{return null}},E=e=>{let t=e.match(/^(\d+)\.(\d+)(?:\.(\d+))?(?:-(.+)|\.(.+))?$/);return t?{major:Number.parseInt(t[1],10),minor:Number.parseInt(t[2],10),patch:t[3]?Number.parseInt(t[3],10):0,prerelease:t[4]||t[5]||``}:null},D=(e,t)=>{let n=E(e),r=E(t);return!n||!r?0:n.major===r.major?n.minor===r.minor?n.patch===r.patch?n.prerelease&&!r.prerelease?-1:!n.prerelease&&r.prerelease?1:0:n.patch-r.patch:n.minor-r.minor:n.major-r.major},it=(e,t)=>{let n=E(e);if(!n||n.prerelease)return!1;if(t===`*`)return!0;let r=t.trim();if(r.startsWith(`~>`)){let t=r.slice(2).trim(),i=E(t);return i?t.split(`.`).length>=3?n.major===i.major&&n.minor===i.minor&&n.patch>=i.patch:n.major===i.major&&n.minor>=i.minor&&D(e,`${i.major}.${i.minor}.0`)>=0:!1}if(r.startsWith(`>=`))return D(e,r.slice(2).trim())>=0;if(r.startsWith(`>`)&&!r.startsWith(`>=`))return D(e,r.slice(1).trim())>0;if(r.startsWith(`<=`))return D(e,r.slice(2).trim())<=0;if(r.startsWith(`<`)&&!r.startsWith(`<=`))return D(e,r.slice(1).trim())<0;if(r.startsWith(`=`)){let e=E(r.slice(1).trim());return e?n.major===e.major&&n.minor===e.minor&&n.patch===e.patch:!1}let i=E(r);return i?n.major===i.major&&n.minor===i.minor&&n.patch===i.patch:!1},at=(e,t)=>{let n=e.filter(e=>it(e,t)).sort(D);return n.length>0?n[n.length-1]:null},ot=e=>{if(e.versions.length===0)return null;let t=e.versions[0],n=t.source.includes(`#devDependencies`);return{current:t.resolved,specifier:t.specifier,isDevDependency:n}},st=async(e,t={})=>{let n=t.cache??!0,r=[],i=e.filter(e=>e.versions.some(e=>e.source.includes(`#dependencies`)||e.source.includes(`#devDependencies`))).map(async e=>{let t=ot(e);if(!t)return;let i=await rt(e.name,!n);if(!i)return;let a=at(i.versions,t.specifier),o=i.latest,s=a&&a!==t.current,c=o&&o!==t.current;if(s||c){let n=a||t.current;r.push({...e,wanted:n,latest:o,specifier:t.specifier,isDevDependency:t.isDevDependency,currentDate:i.versionDates?.[t.current],wantedDate:i.versionDates?.[n],latestDate:i.versionDates?.[o]})}});return await Promise.all(i),r},ct=e=>{let t=[],n=e.split(`
|
|
2
|
+
`),r=`dependencies`,i=0;for(let e of n){let n=e.trim();if(n.startsWith(`#`)||n===``)continue;if(n.startsWith(`group `)){(n.includes(`:development`)||n.includes(`:test`))&&(r=`devDependencies`),n.includes(` do`)&&i++;continue}if(n===`end`){i--,i<=0&&(r=`dependencies`,i=0);continue}let a=n.match(/^gem\s+['"]([^'"]+)['"](?:\s*,\s*['"]([^'"]+)['"])?/);if(a){let e=a[1],n=a[2]||`*`;t.push({name:e,specifier:n,group:r})}}return t},lt=e=>{let t={},n={},r=e.split(`
|
|
3
|
+
`),i=`none`,a=null,o=null;for(let e of r){let r=e.trimEnd();if(r===`GEM`){i=`gem`;continue}if(r===`PLATFORMS`){i=`platforms`;continue}if(r===`DEPENDENCIES`){i=`dependencies`;continue}if(r===`BUNDLED WITH`){i=`none`;continue}if(i===`gem`&&r===` specs:`){i=`specs`;continue}if(i===`specs`){if(r===``)continue;let n=e.match(/^(\s*)/),i=n?n[1].length:0,s=e.trim();if(i===4){let e=s.match(/^([^\s(]+)\s+\(([^)]+)\)/);if(e){let n=e[2],r=n.match(/^[\d.]+/),i=r?r[0]:n;a=e[1],o=i,t[a]||(t[a]={version:i,dependencies:{}})}}else if(i===6&&a&&o){let e=s.match(/^([^\s(]+)(?:\s+\(([^)]+)\))?/);if(e){let n=e[1],r=e[2]||`*`;t[a].dependencies[n]=r}}}if(i===`dependencies`){if(r===``||r.startsWith(` `)===!1)continue;let e=r.match(/^\s+([^\s(!]+)(?:\s+\(([^)]+)\))?/);if(e){let t=e[1].replace(/!$/,``);n[t]=e[2]||`*`}}}return{specs:t,dependencies:n}},ut=async e=>{let t=`${e.path}/Gemfile`,n=`${e.path}/Gemfile.lock`,i;try{i=await(0,r.readFile)(t,`utf-8`)}catch{return[]}let a=new Map,o=new Set,s=ct(i),c=(e,t,n,r,i,o)=>{let s=a.get(e);s?s.versions.push({resolved:r,specifier:o,source:i}):a.set(e,{id:e,name:t,ecosystem:n,versions:[{resolved:r,specifier:o,source:i}]})};a.set(`rubygems:bundler`,{id:`rubygems:bundler`,name:`bundler`,ecosystem:`system`,versions:[]});for(let e of s)o.add(e.name);let l=null;try{l=await(0,r.readFile)(n,`utf-8`)}catch{}if(l){let e=lt(l);for(let t of s){let n=e.specs[t.name];n&&c(`rubygems:${t.name}`,t.name,`rubygems`,n.version,`.#${t.group}`,t.specifier)}for(let[t,n]of Object.entries(e.specs))if(!o.has(t)){for(let[r,i]of Object.entries(e.specs))if(i.dependencies[t]){let e=`Gemfile.lock:${r}@${i.version}`,a=i.dependencies[t];c(`rubygems:${t}`,t,`rubygems`,n.version,e,a)}}}else for(let e of s)c(`rubygems:${e.name}`,e.name,`rubygems`,e.specifier,`.#${e.group}`,e.specifier);return Array.from(a.values()).sort((e,t)=>e.name.localeCompare(t.name))},dt=new Map,ft=T({name:`ruby`,actions:async e=>{let n=e.rootFiles,r=n.includes(`Gemfile`),i=n.includes(`Rakefile`),a=n.includes(`config.ru`),o=await t.n(`${e.path}/config/application.rb`);if(!(r||i))return{};let s={install:[`bundle install`],update:[`bundle update`],outdated:[`bundle outdated`]};return o&&(s.dev=[`bundle exec rails server`],s.repl=[`bundle exec rails console`]),a&&!o&&(s.dev=[`bundle exec rackup`]),s},dependencies:async e=>{if(!e.rootFiles.includes(`Gemfile`))return[];let t=dt.get(e.path);if(t)return t;let n=await ut(e);return dt.set(e.path,n),n},outdatedDependencies:async(e,t)=>{if(!e.rootFiles.includes(`Gemfile`))return[];let n=await ft.dependencies?.(e);return n?st(n,t):[]}}),pt=async()=>{let e=`${(0,i.homedir)()}/.cache/denvig/dependencies/pypi`;return await(0,r.mkdir)(e,{recursive:!0}),e},mt=e=>{let t=e.toLowerCase().replace(/[-_.]+/g,`-`);return t=t.replace(/[^a-zA-Z0-9-]/g,`_`),t=t.replace(/\.{2,}/g,`_`),t=t.replace(/^\.+/,`_`),t.length===0&&(t=`_empty_`),t.length>200&&(t=t.slice(0,200)),t},ht=async e=>{let t=mt(e);return`${await pt()}/${t}.json`},gt=async e=>{try{let t=await(0,r.stat)(e);return Date.now()-t.mtimeMs<36e5}catch{return!1}},_t=async e=>{let t=await ht(e);if(!await gt(t))return null;try{let e=await(0,r.readFile)(t,`utf-8`),n=JSON.parse(e);return n.versionDates?n:null}catch{return null}},vt=async(e,t)=>{try{await(0,r.writeFile)(await ht(e),JSON.stringify(t),`utf-8`)}catch{}},yt=async(e,t=!1)=>{let n=e.toLowerCase().replace(/_/g,`-`);if(!t){let e=await _t(n);if(e)return e}try{let e=await fetch(`https://pypi.org/pypi/${encodeURIComponent(n)}/json`,{headers:{Accept:`application/json`}});if(!e.ok)return null;let t=await e.json(),r=Object.entries(t.releases).filter(([,e])=>e.length>0).map(([e])=>e),i=t.info?.version||r[r.length-1],a={};for(let[e,n]of Object.entries(t.releases))n.length>0&&n[0].upload_time_iso_8601&&(a[e]=n[0].upload_time_iso_8601);let o={versions:r,latest:i,versionDates:a};return await vt(n,o),o}catch{return null}},O=e=>{let t=e.match(/^(\d+)\.(\d+)(?:\.(\d+))?(?:\.(\d+))?(.*)$/);return t?{major:Number.parseInt(t[1],10),minor:Number.parseInt(t[2],10),patch:t[3]?Number.parseInt(t[3],10):0,prerelease:t[5]||``}:null},k=(e,t)=>{let n=O(e),r=O(t);return!n||!r?0:n.major===r.major?n.minor===r.minor?n.patch===r.patch?n.prerelease&&!r.prerelease?-1:!n.prerelease&&r.prerelease?1:0:n.patch-r.patch:n.minor-r.minor:n.major-r.major},bt=e=>/[a-zA-Z]/.test(e),xt=(e,t)=>{let n=O(e);if(!n||bt(e))return!1;if(t===`*`)return!0;if(t.startsWith(`~=`)){let e=t.slice(2).trim(),r=O(e);return r?e.split(`.`).length>=3?n.major===r.major&&n.minor===r.minor&&n.patch>=r.patch:n.major===r.major&&n.minor>=r.minor:!1}if(t.startsWith(`>=`))return k(e,t.slice(2).trim())>=0;if(t.startsWith(`>`)&&!t.startsWith(`>=`))return k(e,t.slice(1).trim())>0;if(t.startsWith(`<=`))return k(e,t.slice(2).trim())<=0;if(t.startsWith(`<`)&&!t.startsWith(`<=`))return k(e,t.slice(1).trim())<0;if(t.startsWith(`!=`))return k(e,t.slice(2).trim())!==0;if(t.startsWith(`==`)){let r=t.slice(2).trim();if(r.endsWith(`.*`)){let t=r.slice(0,-2);return e.startsWith(t)}let i=O(r);return i?n.major===i.major&&n.minor===i.minor&&n.patch===i.patch:!1}let r=O(t);return r?n.major===r.major&&n.minor===r.minor&&n.patch===r.patch:!1},St=(e,t)=>{let n=e.filter(e=>xt(e,t)).sort(k);return n.length>0?n[n.length-1]:null},Ct=e=>{if(e.versions.length===0)return null;let t=e.versions[0],n=t.source.includes(`#devDependencies`);return{current:t.resolved,specifier:t.specifier,isDevDependency:n}},wt=async(e,t={})=>{let n=t.cache??!0,r=[],i=e.filter(e=>e.versions.some(e=>e.source.includes(`#dependencies`)||e.source.includes(`#devDependencies`))).map(async e=>{let t=Ct(e);if(!t)return;let i=await yt(e.name,!n);if(!i)return;let a=St(i.versions,t.specifier),o=i.latest,s=a&&a!==t.current,c=o&&o!==t.current;if(s||c){let n=a||t.current;r.push({...e,wanted:n,latest:o,specifier:t.specifier,isDevDependency:t.isDevDependency,currentDate:i.versionDates?.[t.current],wantedDate:i.versionDates?.[n],latestDate:i.versionDates?.[o]})}});return await Promise.all(i),r},Tt=e=>{let t=e.trim();return t.startsWith(`"`)&&t.endsWith(`"`)||t.startsWith(`'`)&&t.endsWith(`'`)?t.slice(1,-1):t},A=e=>{let t=e.trim();return t===`true`?!0:t===`false`?!1:/^-?\d+$/.test(t)?Number.parseInt(t,10):/^-?\d+\.\d+$/.test(t)?Number.parseFloat(t):Tt(t)},j=e=>{let t={},n=e.slice(1,-1).trim();if(!n)return t;let r=[],i=``,a=0,o=!1,s=``;for(let e=0;e<n.length;e++){let t=n[e];if(!o&&(t===`"`||t===`'`)?(o=!0,s=t):o&&t===s&&n[e-1]!==`\\`&&(o=!1),!o){if(t===`{`||t===`[`)a++;else if(t===`}`||t===`]`)a--;else if(t===`,`&&a===0){r.push(i.trim()),i=``;continue}}i+=t}i.trim()&&r.push(i.trim());for(let e of r){let n=e.indexOf(`=`);if(n===-1)continue;let r=e.slice(0,n).trim(),i=e.slice(n+1).trim();i.startsWith(`{`)?t[r]=j(i):i.startsWith(`[`)?t[r]=M(i):t[r]=A(i)}return t},M=e=>{let t=[],n=e.slice(1,-1).trim();if(!n)return t;let r=[],i=``,a=0,o=!1,s=``;for(let e=0;e<n.length;e++){let t=n[e];if(!o&&(t===`"`||t===`'`)?(o=!0,s=t):o&&t===s&&n[e-1]!==`\\`&&(o=!1),!o){if(t===`{`||t===`[`)a++;else if(t===`}`||t===`]`)a--;else if(t===`,`&&a===0){r.push(i.trim()),i=``;continue}}i+=t}i.trim()&&r.push(i.trim());for(let e of r){let n=e.trim();n.startsWith(`{`)?t.push(j(n)):n.startsWith(`[`)?t.push(M(n)):t.push(A(n))}return t},Et=(e,t,n)=>{let r=e;for(let e=0;e<t.length-1;e++){let n=t[e];(!(n in r)||typeof r[n]!=`object`)&&(r[n]={}),r=r[n]}r[t[t.length-1]]=n},N=(e,t)=>{let n=e;for(let e of t)(!(e in n)||typeof n[e]!=`object`)&&(n[e]={}),n=n[e];return n},Dt=e=>{let t={},n=e.split(`
|
|
4
|
+
`),r=[],i=null,a=null,o=null,s=null;for(let e=0;e<n.length;e++){let c=n[e];if(o!==null&&s!==null){if(o+=c,c.includes(`]`)){let e=0,n=-1;for(let t=0;t<o.length;t++)if(o[t]===`[`)e++;else if(o[t]===`]`&&(e--,e===0)){n=t;break}if(n!==-1){let e=M(o.slice(0,n+1));a?a[s]=e:Et(t,[...r,s],e),o=null,s=null}}continue}let l=c.indexOf(`#`);if(l!==-1){let e=!1,t=``;for(let n=0;n<l;n++){let r=c[n];!e&&(r===`"`||r===`'`)?(e=!0,t=r):e&&r===t&&c[n-1]!==`\\`&&(e=!1)}e||(c=c.slice(0,l))}if(c=c.trim(),!c)continue;if(c.startsWith(`[[`)&&c.endsWith(`]]`)){if(a&&i){let e=N(t,i.slice(0,-1)),n=i[i.length-1];Array.isArray(e[n])||(e[n]=[]),e[n].push(a)}i=c.slice(2,-2).split(`.`),a={},r=[];continue}if(c.startsWith(`[`)&&c.endsWith(`]`)){if(a&&i){let e=N(t,i.slice(0,-1)),n=i[i.length-1];Array.isArray(e[n])||(e[n]=[]),e[n].push(a),a=null,i=null}r=c.slice(1,-1).split(`.`),N(t,r);continue}let u=c.indexOf(`=`);if(u===-1)continue;let d=c.slice(0,u).trim(),f=c.slice(u+1).trim();if(f.startsWith(`[`)&&!f.endsWith(`]`)){o=f,s=d;continue}let p;p=f.startsWith(`{`)?j(f):f.startsWith(`[`)?M(f):A(f),a?a[d]=p:Et(t,[...r,d],p)}if(a&&i){let e=N(t,i.slice(0,-1)),n=i[i.length-1];Array.isArray(e[n])||(e[n]=[]),e[n].push(a)}return t},P=e=>e.toLowerCase().replace(/_/g,`-`),F=e=>{let t=e.match(/^([a-zA-Z0-9_-]+(?:\[[^\]]+\])?)(.*)$/);return t?{name:t[1].replace(/\[.*\]$/,``),specifier:t[2].trim()||`*`}:{name:e,specifier:`*`}},Ot=e=>{let t=[];try{let n=Dt(e);if(n.project?.dependencies)for(let e of n.project.dependencies){let{name:n,specifier:r}=F(e);t.push({name:n,specifier:r,group:`dependencies`})}if(n.tool?.uv?.[`dev-dependencies`])for(let e of n.tool.uv[`dev-dependencies`]){let{name:n,specifier:r}=F(e);t.push({name:n,specifier:r,group:`devDependencies`})}if(n.project?.[`optional-dependencies`])for(let e of Object.values(n.project[`optional-dependencies`]))for(let n of e){let{name:e,specifier:r}=F(n);t.push({name:e,specifier:r,group:`devDependencies`})}}catch{}return t},kt=e=>{let t={},n=null;try{let r=Dt(e);if(r.package)for(let e of r.package){let r=P(e.name);e.source?.virtual&&(n=r);let i=e.dependencies?.map(e=>P(e.name))||[];t[r]={name:e.name,version:e.version,dependencies:i}}}catch{}return{packages:t,projectName:n}},At=async e=>{let t=`${e.path}/pyproject.toml`,n=`${e.path}/uv.lock`,i;try{i=await(0,r.readFile)(t,`utf-8`)}catch{return[]}let a=new Map,o=new Set,s=(e,t,n,r,i,o)=>{let s=a.get(e);s?s.versions.push({resolved:r,specifier:o,source:i}):a.set(e,{id:e,name:t,ecosystem:n,versions:[{resolved:r,specifier:o,source:i}]})};a.set(`pypi:uv`,{id:`pypi:uv`,name:`uv`,ecosystem:`system`,versions:[]});let c=Ot(i);for(let e of c)o.add(P(e.name));let l=null;try{l=await(0,r.readFile)(n,`utf-8`)}catch{}if(l){let e=kt(l);for(let t of c){let n=P(t.name),r=e.packages[n];r&&s(`pypi:${n}`,r.name,`pypi`,r.version,`.#${t.group}`,t.specifier)}for(let[t,n]of Object.entries(e.packages))if(!(t===e.projectName||o.has(t))){for(let[,r]of Object.entries(e.packages))if(r.dependencies.includes(t)){let e=`uv.lock:${r.name}@${r.version}`;s(`pypi:${t}`,n.name,`pypi`,n.version,e,`*`)}}}else for(let e of c)s(`pypi:${P(e.name)}`,e.name,`pypi`,e.specifier,`.#${e.group}`,e.specifier);return Array.from(a.values()).sort((e,t)=>e.name.localeCompare(t.name))},jt=new Map,Mt=T({name:`uv`,actions:async e=>{let t=e.rootFiles,n=t.includes(`pyproject.toml`);return t.includes(`uv.lock`)||n?{install:[`uv sync`]}:{}},dependencies:async e=>{let t=e.rootFiles.includes(`pyproject.toml`),n=e.rootFiles.includes(`uv.lock`);if(!t&&!n)return[];let r=jt.get(e.path);if(r)return r;let i=await At(e);return jt.set(e.path,i),i},outdatedDependencies:async(e,t)=>{if(!e.rootFiles.includes(`pyproject.toml`))return[];let n=await Mt.dependencies?.(e);return n?wt(n,t):[]}}),Nt=e=>{let t=e.split(`
|
|
5
|
+
|
|
6
|
+
`),n={};for(let e of t){let t=e.split(`
|
|
7
|
+
`);if(t.length<3)continue;let r=t[0].split(`,`).map(e=>e.trim().replace(/"|:/g,``)),i=t[1]?.match(/version "(.+)"/)?.[1],a=t[2]?.match(/resolved "(.+)"/)?.[1];if(!(!i||!a))for(let e of r)e&&(n[e]={version:i,resolved:a})}return{type:`success`,object:n}},Pt=e=>{let t={},n=Nt(e);for(let[e,r]of Object.entries(n.object)){let[,n,i]=e.match(/^(@?.+)@(.+)$/)||[];t[n]||(t[n]={versions:{}}),t[n].versions[r.version]||(t[n].versions[r.version]=[]),t[n].versions[r.version]=[...t[n].versions[r.version],i].sort((e,t)=>e.localeCompare(t,void 0,{numeric:!0})),t[n].versions=Object.fromEntries(Object.entries(t[n].versions).sort((e,t)=>e[0].localeCompare(t[0],void 0,{numeric:!0})))}for(let[e,n]of Object.entries(t))t[e].optimisedVersions=Ne(n.versions);return{dependencies:t}},Ft=(e,t)=>{let n=[],r=e.split(`
|
|
8
|
+
|
|
9
|
+
`);for(let e of r){let r=e.split(`
|
|
10
|
+
`);if(r.length<3){n.push(e);continue}let i=r[0].split(`,`).map(e=>e.trim().replace(/"|:/g,``)),a=r[1]?.match(/version "(.+)"/)?.[1],o=r[2]?.match(/resolved "(.+)"/)?.[1],s=/^(@?.+)@(.+)$/;if(!a||!o||i.length===0){n.push(e);continue}let[,c]=i[0].match(s)||[];t[c]?.includes(a)||n.push(e)}return n.join(`
|
|
11
|
+
|
|
12
|
+
`)},It=e=>{let t=e.split(`
|
|
13
|
+
|
|
14
|
+
`),n={};for(let e of t){let t=e.split(`
|
|
15
|
+
`);if(t.length<3)continue;let r=t[0].split(`,`).map(e=>e.trim().replace(/"|:/g,``)),i=t[1]?.match(/version "(.+)"/)?.[1],a=t[2]?.match(/resolved "(.+)"/)?.[1];if(!i||!a)continue;let o={},s=!1;for(let e=3;e<t.length;e++){let n=t[e];if(n.trim()===`dependencies:`){s=!0;continue}if(s&&n.startsWith(` `)){let e=n.trim().match(/^"?([^"\s]+)"?\s+"?([^"]+)"?$/);e&&(o[e[1]]=e[2])}else s&&!n.startsWith(` `)&&(s=!1)}for(let e of r)e&&(n[e]={version:i,resolved:a,dependencies:Object.keys(o).length>0?o:void 0})}return{type:`success`,object:n}},Lt=e=>{let t={},n=It(e),r=new Map;for(let[e,t]of Object.entries(n.object)){let[,n,i]=e.match(/^(@?.+)@(.+)$/)||[];n&&(r.has(n)||r.set(n,[]),r.get(n)?.push({version:t.version,specifier:i,deps:t.dependencies}))}for(let[e,n]of r.entries()){t[e]||(t[e]={versions:{}});for(let r of n)t[e].versions[r.version]||(t[e].versions[r.version]={}),t[e].versions[r.version][`yarn.lock`]=r.specifier;t[e].versions=Object.fromEntries(Object.entries(t[e].versions).sort((e,t)=>e[0].localeCompare(t[0],void 0,{numeric:!0})))}for(let[e,n]of r.entries())for(let i of n){if(!i.deps)continue;let n=`${e}@${i.version}`;for(let[e,a]of Object.entries(i.deps)){t[e]||(t[e]={versions:{}});let i=r.get(e);if(!i)continue;let o=i.find(e=>e.specifier===a)?.version||i[0]?.version;if(o){t[e].versions[o]||(t[e].versions[o]={});let r=`yarn.lock:${n}`;t[e].versions[o][r]=a}}}return{dependencies:t}},Rt=new Map;function zt(e){return e.includes(`__metadata:`)}function Bt(e){let t=e.match(/^(.+)@npm:/);if(t)return t[1];let n=e.lastIndexOf(`@`);return n>0?e.slice(0,n):e}const Vt=T({name:`yarn`,actions:async e=>{let t=e.rootFiles.includes(`package.json`),n=e.rootFiles.includes(`yarn.lock`);if(!(t&&n))return{};let r=(await w(e))?.scripts||{};return{...Object.entries(r).map(([e,t])=>[e,`yarn run ${e}`]).reduce((e,[t,n])=>(e[t]=[n],e),{}),install:[`yarn install`],outdated:[`yarn outdated`]}},dependencies:async e=>{let n=`${e.path}/yarn.lock`,i=`${e.path}/package.json`;if(!await t.n(n)||!await t.n(i))return[];let a=Rt.get(e.path);if(a)return a;let s=new Map,c=new Set,l=(e,t,n,r,i,a)=>{let o=s.get(e);o?o.versions.push({resolved:r,specifier:a,source:i}):s.set(e,{id:e,name:t,ecosystem:n,versions:[{resolved:r,specifier:a,source:i}]})};s.set(`npm:yarn`,{id:`npm:yarn`,name:`yarn`,ecosystem:`system`,versions:[]});let u=await(0,r.readFile)(n,`utf-8`),d=zt(u),f=new Map,p=new Map,m=null;if(d){let e=(0,o.parse)(u);for(let[t,n]of Object.entries(e)){if(t===`__metadata`||!n?.version||typeof n.version!=`string`)continue;let e=Bt(t),r=n;f.has(e)||f.set(e,new Map);let i=t.match(/@npm:(.+)$/);i&&f.get(e)?.set(i[1],n.version),r.dependencies&&p.set(`${e}@${r.version}`,r.dependencies)}}else{m=Lt(u);for(let[e,t]of Object.entries(m.dependencies)){f.has(e)||f.set(e,new Map);for(let[n,r]of Object.entries(t.versions)){let t=r[`yarn.lock`];t&&f.get(e)?.set(t,n)}}}let h=[i],g=await e.findFilesByName(`package.json`);h.push(...g);for(let t of h)try{let n=await(0,r.readFile)(t,`utf-8`),a=JSON.parse(n),o=`.`;t!==i&&(o=t.replace(`${e.path}/`,``).replace(`/package.json`,``));let s=(e,t)=>{if(e)for(let[n,r]of Object.entries(e)){c.add(n);let e=f.get(n),i=r;if(e){let t=e.get(r);if(t)i=t;else{let t=e.values().next().value;t&&(i=t)}}l(`npm:${n}`,n,`npm`,i,`${o}#${t}`,r)}};s(a.dependencies,`dependencies`),s(a.devDependencies,`devDependencies`)}catch{}if(d){for(let[e,t]of p.entries())for(let[n,r]of Object.entries(t))if(!c.has(n)){let t=f.get(n),i=r;if(t){let e=t.get(r);if(e)i=e;else{let e=t.values().next().value;e&&(i=e)}}let a=`yarn.lock:${e}`;l(`npm:${n}`,n,`npm`,i,a,r)}}else if(m){for(let[e,t]of Object.entries(m.dependencies))if(!c.has(e))for(let[n,r]of Object.entries(t.versions))for(let[t,i]of Object.entries(r))t.startsWith(`yarn.lock:`)&&l(`npm:${e}`,e,`npm`,n,t,i)}let _=Array.from(s.values()).sort((e,t)=>e.name.localeCompare(t.name));return Rt.set(e.path,_),_},outdatedDependencies:async(e,n)=>{if(!await t.n(`${e.path}/yarn.lock`))return[];let r=await Vt.dependencies?.(e);return r?he(r,n):[]},deduplicateDependencies:async(e,n)=>{let i=`${e.path}/yarn.lock`;if(!await t.n(i))return null;let a=await(0,r.readFile)(i,`utf-8`),o=Ae(Pt(a)),s=n?.dryRun??!1,c=!1;return!s&&Object.keys(o.removals).length>0&&(await je(i,Ft(a,o.removals),`yarn`),c=!0),{ecosystem:`yarn.lock`,...o,applied:c}}});var I={deno:Oe,npm:ke,pnpm:Xe,ruby:ft,uv:Mt,yarn:Vt};const L=(0,c.promisify)(n.exec);function R(){return`gui/${process.getuid?.()??501}`}async function Ht(e){try{let{stdout:t,stderr:n}=await L(`launchctl bootstrap ${R()} "${e}"`);return{success:!0,output:t||n}}catch(e){let t=e;return{success:!1,output:t.stderr||t.message||`Unknown error`}}}async function Ut(e){try{let{stdout:t,stderr:n}=await L(`launchctl bootout ${R()}/${e}`);return{success:!0,output:t||n}}catch(e){let t=e;return{success:!1,output:t.stderr||t.message||`Unknown error`}}}async function Wt(e){try{let{stdout:t,stderr:n}=await L(`launchctl start ${e}`);return{success:!0,output:t||n}}catch(e){let t=e;return{success:!1,output:t.stderr||t.message||`Unknown error`}}}async function Gt(e){try{let{stdout:t,stderr:n}=await L(`launchctl stop ${e}`);return{success:!0,output:t||n}}catch(e){let t=e;return{success:!1,output:t.stderr||t.message||`Unknown error`}}}async function Kt(e){try{let{stdout:t,stderr:n}=await L(`launchctl enable ${R()}/${e}`);return{success:!0,output:t||n}}catch(e){let t=e;return{success:!1,output:t.stderr||t.message||`Unknown error`}}}async function qt(e){try{let{stdout:t,stderr:n}=await L(`launchctl disable ${R()}/${e}`);return{success:!0,output:t||n}}catch(e){let t=e;return{success:!1,output:t.stderr||t.message||`Unknown error`}}}async function Jt(e){try{let{stdout:t}=await L(`launchctl print ${R()}/${e}`),n=t.match(/pid\s*=\s*(\d+)/),r=t.match(/state\s*=\s*(\w+)/),i=t.match(/last exit code\s*=\s*(\d+)/);return{label:e,pid:n?parseInt(n[1],10):void 0,state:r?r[1]:`unknown`,status:r?r[1]:`unknown`,lastExitCode:i?parseInt(i[1],10):void 0}}catch{return null}}async function Yt(e){try{let{stdout:t}=await L(`launchctl list`),n=t.trim().split(`
|
|
16
|
+
`).slice(1).map(e=>{let t=e.trim().split(/\s+/);return t.length<3?null:{pid:t[0]===`-`?`-`:parseInt(t[0],10),status:parseInt(t[1],10),label:t[2]}}).filter(e=>e!==null);return e?n.filter(t=>t.label.includes(e)):n}catch{return[]}}var z={bootstrap:Ht,bootout:Ut,enable:Kt,disable:qt,start:Wt,stop:Gt,print:Jt,list:Yt,getUserDomain:R};let Xt;const B=async()=>(Xt||=(await import(`node-forge`)).default,Xt),Zt=process.env.HOME||``,V=()=>(0,a.resolve)(`${Zt}/.denvig/ca`),H=()=>(0,a.resolve)(`${Zt}/.denvig/certs`),U=()=>(0,a.resolve)(V(),`rootCA-key.pem`),W=()=>(0,a.resolve)(V(),`rootCA.pem`),Qt=e=>{let t=e.replace(/^\*/,`_wildcard`);return(0,a.resolve)(H(),t)},$t=async()=>{let e=await B(),[t,n]=await Promise.all([(0,r.readFile)(W(),`utf-8`),(0,r.readFile)(U(),`utf-8`)]);return{cert:e.pki.certificateFromPem(t),key:e.pki.privateKeyFromPem(n)}},en=async()=>{let e=await B(),t=e.pki.rsa.generateKeyPair(2048),n=e.pki.createCertificate();n.publicKey=t.publicKey,n.serialNumber=await mn();let r=new Date;n.validity.notBefore=r,n.validity.notAfter=new Date(r.getFullYear()+10,r.getMonth(),r.getDate());let i=[{name:`organizationName`,value:`denvig.com`},{name:`commonName`,value:`Denvig Local CA`}];return n.setSubject(i),n.setIssuer(i),n.setExtensions([{name:`basicConstraints`,cA:!0,critical:!0},{name:`keyUsage`,keyCertSign:!0,cRLSign:!0,critical:!0}]),n.sign(t.privateKey,e.md.sha256.create()),{cert:n,key:t.privateKey,certPem:e.pki.certificateToPem(n),keyPem:e.pki.privateKeyToPem(t.privateKey)}},tn=async(e,t,n)=>{let r=await B(),i=r.pki.rsa.generateKeyPair(2048),a=r.pki.createCertificate();a.publicKey=i.publicKey,a.serialNumber=await mn();let o=new Date;a.validity.notBefore=o,a.validity.notAfter=new Date(o.getTime()+720*24*60*60*1e3),a.setSubject([{name:`commonName`,value:e}]),a.setIssuer(t.subject.attributes),a.setExtensions([{name:`basicConstraints`,cA:!1},{name:`keyUsage`,digitalSignature:!0,keyEncipherment:!0,critical:!0},{name:`extKeyUsage`,serverAuth:!0},{name:`subjectAltName`,altNames:[{type:2,value:e}]}]),a.sign(n,r.md.sha256.create());let s=r.pki.certificateToPem(a),c=r.pki.certificateToPem(t);return{privkey:r.pki.privateKeyToPem(i.privateKey),fullchain:s+c}},nn=e=>{(0,n.execSync)(`sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${e}`,{stdio:`inherit`})},rn=e=>{(0,n.execSync)(`sudo security remove-trusted-cert -d ${e}`,{stdio:`inherit`})},G=e=>{let t=e.match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/);return t?t[0]:e},an=e=>{let t=new l.X509Certificate(G(e)),n=[],r=t.subjectAltName;if(r)for(let e of r.split(`,`)){let t=e.trim();t.startsWith(`DNS:`)&&n.push(t.slice(4))}if(n.length===0){let e=t.subject.match(/CN=([^,\n]+)/);e&&n.push(e[1])}return n},on=e=>{let t=new l.X509Certificate(G(e));return new Date(t.validTo)},sn=async(e,t)=>{await(0,r.mkdir)(V(),{recursive:!0}),await Promise.all([(0,r.writeFile)(U(),t,{mode:384}),(0,r.writeFile)(W(),e)])},cn=async(e,t,n)=>{let i=Qt(e);return await(0,r.mkdir)(i,{recursive:!0}),await Promise.all([(0,r.writeFile)((0,a.resolve)(i,`privkey.pem`),t,{mode:384}),(0,r.writeFile)((0,a.resolve)(i,`fullchain.pem`),n)]),i},ln=async()=>{let[e,n]=await Promise.all([t.n(W()),t.n(U())]);return e&&n},un=async()=>{let e=W();return await t.n(e)?(0,n.spawnSync)(`security`,[`verify-cert`,`-c`,e],{stdio:`pipe`}).status===0:!1},dn=(e,t)=>{try{let n=new l.X509Certificate(G(e)),r=new l.X509Certificate(G(t));return n.checkIssued(r)&&n.verify(r.publicKey)}catch{return!1}},fn=e=>{try{let t=new l.X509Certificate(G(e));return t.issuer.includes(`CN=Denvig Local CA`)&&t.issuer.includes(`O=denvig.com`)}catch{return!1}},pn=e=>{try{let t=new l.X509Certificate(G(e)).issuer.match(/CN=([^,\n]+)/);return t?t[1]:null}catch{return null}},mn=async()=>{let e=await B();return e.util.bytesToHex(e.random.getBytesSync(16))},hn=e=>{let t=(0,a.resolve)(e,`fullchain.pem`),n=(0,a.resolve)(e,`cert.pem`);try{return(0,u.statSync)(t),t}catch{}try{return(0,u.statSync)(n),n}catch{}return null},gn=(e,t=new Date)=>{let n=H(),r;try{r=(0,u.readdirSync)(n).filter(e=>{try{return(0,u.statSync)((0,a.resolve)(n,e)).isDirectory()}catch{return!1}})}catch{return 0}let i=t.getTime()+e,o=0;for(let e of r){let t=hn((0,a.resolve)(n,e));if(t)try{on((0,u.readFileSync)(t,`utf-8`)).getTime()<=i&&o++}catch{}}return o};function _n(e,t){return!!(e===t||t.startsWith(`*.`)&&e.endsWith(t.slice(1))&&!e.slice(0,-t.length+1).includes(`.`))}async function K(e){let n=H();if(!await t.n(n))return null;let i;try{i=(await(0,r.readdir)(n,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name)}catch{return null}for(let o of i){let i=(0,a.resolve)(n,o,`fullchain.pem`);if(await t.n(i))try{if(an(await(0,r.readFile)(i,`utf-8`)).some(t=>_n(e,t)))return(0,a.resolve)(n,o)}catch{}}return null}function vn(e){let t=e.split(`.`);return t.length<=2?e:t.slice(1).join(`.`)}function yn(e){let t=new Map;for(let n of e){let e=vn(n);t.has(e)||t.set(e,[]),t.get(e)?.push(n)}let n=new Map;for(let[e,r]of t)if(r.some(t=>t!==e)&&r.length>=2)n.set(`*.${e}`,r);else for(let e of r)n.set(e,[e]);return n}async function bn(e){let t=new Map,n=[];for(let r of e){let e=await K(r);e?t.set(r,e):n.push(r)}if(n.length===0||!await ln())return t;let{cert:r,key:i}=await $t(),a=yn(n);for(let[e,n]of a){let{privkey:a,fullchain:o}=await tn(e,r,i),s=await cn(e,a,o);for(let e of n)t.set(e,s)}return t}async function xn(e){let n=(0,a.resolve)(e,`fullchain.pem`),r=(0,a.resolve)(e,`privkey.pem`),[i,o]=await Promise.all([t.n(n),t.n(r)]);return i&&o?{sslCertPath:n,sslKeyPath:r}:null}const Sn=[`build`,`check-types`,`dev`,`install`,`lint`,`outdated`,`test`],Cn=d.z.string().max(64,`Service name must be 64 characters or less`).regex(/^[a-z]([a-z0-9-]*[a-z0-9])?$/,`Service name must start with a letter, contain only lowercase alphanumeric and hyphens, and not end with a hyphen`),wn=d.z.object({cwd:d.z.string().optional().describe(`Working directory for the service (relative to project root)`),command:d.z.string().describe(`Shell command to execute`),http:d.z.object({port:d.z.number().optional().describe(`Port number the service listens on`),domain:d.z.string().optional().describe(`Domain to use for the service URL`),cnames:d.z.array(d.z.string()).optional().describe(`Additional hosts that can be used via gateway`),secure:d.z.boolean().optional().describe(`Use HTTPS instead of HTTP`)}).optional().describe(`HTTP configuration for the service URL`),envFiles:d.z.array(d.z.string()).optional().describe(`Paths to .env files (relative to service cwd)`),env:d.z.record(d.z.string(),d.z.string()).optional().describe(`Environment variables`),keepAlive:d.z.boolean().optional().describe(`Restart service if it exits`),startOnBoot:d.z.boolean().optional().describe(`Start service automatically when system boots`)}),Tn=d.z.record(Cn,wn).optional().describe(`Services that can be managed`),En=d.z.object({projectPaths:d.z.array(d.z.string()).optional().default([`~/src/*/*`,`~/.dotfiles`]).describe(`Paths or patterns where projects are located`),quickActions:d.z.array(d.z.string()).default(Sn).optional().describe(`Quick actions that are available for all projects`),services:Tn.describe(`Global services that can be managed from any directory`),experimental:d.z.object({gateway:d.z.object({enabled:d.z.boolean(),handler:d.z.enum([`nginx`]).default(`nginx`),configsPath:d.z.string().default(`/opt/homebrew/etc/nginx/servers`)}).optional()}).optional()}),Dn=d.z.object({name:d.z.string().optional().describe(`Display name for the project`),actions:d.z.record(d.z.string().describe(`Name of the action`),d.z.object({command:d.z.string().describe(`Shell command to run for the action`)})).optional().describe(`Actions that can be run against the project`),quickActions:d.z.array(d.z.string()).optional().describe(`Actions that are available on the CLI root for quick access`),services:Tn}),On=(0,a.resolve)(`${process.env.HOME}/.denvig/config.yml`),kn={projectPaths:[`~/src/*/*`,`~/.dotfiles`],quickActions:void 0},An=e=>e.startsWith(`~/`)?`${process.env.HOME}${e.slice(1)}`:e,jn=()=>{let e={},t=process.env.DENVIG_PROJECT_PATHS;t!==void 0&&(e.projectPaths=t.split(`,`).map(e=>e.trim()).filter(e=>e.length>0));let n=process.env.DENVIG_QUICK_ACTIONS;return n!==void 0&&(n===``?e.quickActions=[]:e.quickActions=n.split(`,`).map(e=>e.trim()).filter(e=>e.length>0)),e},Mn=(e,t)=>{let n=[],r={};if(e)try{let i=(0,o.parse)(e)||{};r={...r,...i},n.push(t)}catch(e){console.error(`Error parsing global config at ${t}:`,e),process.exit(1)}let i=jn();return r={...r,...i},{...En.parse({...kn,...r}),$sources:n}},Nn=()=>{let e=process.env.DENVIG_GLOBAL_CONFIG_PATH;return e?(0,a.resolve)(e):On},q=async()=>{let e=Nn();return Mn(await t.r(e),e)},Pn=async e=>{let n=`${e}/.denvig.yml`,r=await t.r(n);if(r)try{return{...Dn.parse((0,o.parse)(r)),$sources:[n]}}catch{}return{$sources:[]}},J=(e,t,r={})=>new Promise(i=>{let a=(0,n.spawn)(e,t,{cwd:r.cwd,stdio:r.stdio??`inherit`});a.on(`close`,e=>i(e===0)),a.on(`error`,()=>i(!1))}),Fn=(0,c.promisify)(n.execFile),In=e=>{let t=e.match(/^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?$/);if(t)return`${t[1]}/${t[2]}`;let n=e.match(/^https:\/\/github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?$/);return n?`${n[1]}/${n[2]}`:null},Ln=async e=>{let t=a.default.join(e,`.git`,`config`);try{let e=await(0,r.readFile)(t,`utf-8`);for(let t of[`origin`,`github`]){let n=e.match(RegExp(`\\[remote "${t}"\\][^[]*url\\s*=\\s*([^\\s\\n]+)`));if(n){let e=In(n[1]);if(e)return e}}return null}catch{return null}},Rn=(e,t)=>J(`git`,[`clone`,e,t]),zn=e=>J(`git`,[`pull`],{cwd:e}),Bn=async e=>{try{let{stdout:t}=await Fn(`git`,[`status`,`--porcelain`],{cwd:e});return t.trim().length>0}catch{return!1}},Vn=e=>{let t=e.replace(/\.git$/,``),n=t.match(/^[a-z][a-z0-9+.-]*:\/\/(?:[^@/]+@)?([^/]+)\/(.+)$/i);if(n)return`${n[1]}/${n[2]}`;let r=t.match(/^(?:[^@\s/]+@)?([^:\s/]+):(.+)$/);return r?`${r[1]}/${r[2]}`:null},Hn=e=>{let t=e?.match(/^github\.com\/(.+\/.+)$/);return t?t[1]:null},Un=e=>{let t=(0,a.resolve)(e);for(;;){let e=(0,a.resolve)(t,`.git`);try{return(0,u.statSync)(e).isFile()?t:null}catch{}let n=(0,a.resolve)(t,`..`);if(n===t)return null;t=n}},Wn=e=>{let t=Gn((0,a.resolve)(e));if(!t)return[];let n=`${t.primaryGitDir}/worktrees`,r;try{r=(0,u.readdirSync)(n,{withFileTypes:!0})}catch{return[]}let i=[];for(let e of r){if(!e.isDirectory())continue;let t=`${n}/${e.name}`,r=Kn(t);if(!r)continue;let a;try{a=(0,u.readFileSync)(`${t}/gitdir`,`utf-8`).trim()}catch{continue}let o=a.replace(/\/\.git$/,``);i.push({path:o,branch:r})}return i.sort((e,t)=>e.path.localeCompare(t.path))},Gn=e=>{let t=(0,a.resolve)(e,`.git`),n;try{n=(0,u.statSync)(t)}catch{return null}let r,i;if(n.isFile()){let e;try{e=(0,u.readFileSync)(t,`utf-8`).trim()}catch{return null}let n=e.match(/^gitdir:\s*(.+)\/\.git\/worktrees\/([^/]+)$/);if(!n)return null;let a=n[1],o=`${a}/.git/worktrees/${n[2]}`;r=`${a}/.git`;let s=Kn(o);if(!s)return null;i={primaryPath:a,branch:s}}else if(n.isDirectory()){let n;try{n=(0,u.realpathSync)(e)}catch{n=e}r=t,i={primaryPath:n,branch:`main`}}else return null;return{primaryGitDir:r,remotes:qn(`${r}/config`),worktree:i}},Kn=e=>{try{let t=(0,u.readFileSync)(`${e}/HEAD`,`utf-8`).trim().match(/^ref:\s*refs\/heads\/(.+)$/);return t?t[1]:null}catch{return null}},qn=e=>{let t={},n;try{n=(0,u.readFileSync)(e,`utf-8`)}catch{return t}for(let e of n.matchAll(/\[remote\s+"([^"]+)"\][^[]*?url\s*=\s*(\S+)/g))e[1]in t||(t[e[1]]=e[2]);return t},Jn=e=>{let t=[],n=(0,a.resolve)(e),r=Gn(n),i=r?.remotes.origin??null,o=i?Vn(i):null,s=r?.remotes.github??null,c=Hn(o)??Hn(s?Vn(s):null);c&&t.push(`github:${c}`),o&&r?.worktree&&t.push(`git:${o}+${r.worktree.branch}`),t.push(`local:${n}`);let u=(0,l.createHash)(`sha1`).update(t.join(`
|
|
17
|
+
`)).digest(`hex`);return t.push(`id:${u}`),t},Yn=e=>{let t=Jn(e);return t.find(e=>e.startsWith(`github:`))||t.find(e=>e.startsWith(`local:`))},Xn=e=>Jn(e).find(e=>e.startsWith(`id:`)).slice(3),Zn=async e=>{let t={};e.config.actions&&(t={...Object.entries(e.config.actions).reduce((e,[t,n])=>(e[t]=[n.command],e),{})});for(let[n,r]of Object.entries(I)){let n=await r.actions(e);t=v(t,n)}return t},Qn=d.z.object({resolved:d.z.string().describe(`The resolved version of the dependency`),specifier:d.z.string().describe(`The version constraint/specifier used`),source:d.z.string().describe(`The source file/path of the dependency`),wanted:d.z.string().describe(`The wanted version based on semver rules`).optional(),latest:d.z.string().describe(`The latest available version of the dependency`).optional()});d.z.object({id:d.z.string().describe(`Unique identifier for the ecosystem / dependency`),name:d.z.string().describe(`Name of the dependency`),versions:d.z.array(Qn).describe(`Map of resolved versions to sources. Each source maps a package path to its version specifier.`),ecosystem:d.z.string().describe(`Ecosystem of the dependency (e.g., npm, rubygems, pip)`)}).extend({wanted:d.z.string().describe(`Latest version compatible with the specifier (semver)`),latest:d.z.string().describe(`Absolute latest version available`),specifier:d.z.string().describe(`The version specifier from package manifest`),isDevDependency:d.z.boolean().describe(`Whether this is a dev dependency`),currentDate:d.z.string().optional().describe(`ISO date when the current version was published`),wantedDate:d.z.string().optional().describe(`ISO date when the wanted version was published`),latestDate:d.z.string().optional().describe(`ISO date when the latest version was published`)});const $n=e=>{let t=new Map;for(let n of e){let e=t.get(n.id);e?t.set(n.id,{...e,versions:[...e.versions,...n.versions]}):t.set(n.id,n)}return Array.from(t.values())},er=async e=>$n((await Promise.all(Object.values(I).map(t=>t.dependencies?t.dependencies(e):Promise.resolve([])))).flat());var tr=class e{path;branch;isPrimary;refs;slug;id;config;_rootFilesCache=null;constructor(e,t,n,r,i){this.path=e,this.branch=t,this.isPrimary=n,this.refs=Jn(e);let a=this.refs.find(e=>e.startsWith(`github:`)),o=this.refs.find(e=>e.startsWith(`local:`)),s=this.refs.find(e=>e.startsWith(`id:`));this.slug=a??o,this.id=s.slice(3),this.config=r,i&&(this._rootFilesCache=i)}static async retrieve(t,n,i){let[a,o]=await Promise.all([Pn(t),(0,r.readdir)(t).catch(()=>[])]);return new e(t,n,i,a,o)}get name(){return this.config.name??this.path.split(`/`).pop()??`unknown`}get rootFiles(){return this._rootFilesCache??[]}get packageManagers(){let e=this.rootFiles,t=[];return e.includes(`pnpm-lock.yaml`)?t.push(`pnpm`):e.includes(`package-lock.json`)?t.push(`npm`):e.includes(`yarn.lock`)&&t.push(`yarn`),(e.includes(`deno.json`)||e.includes(`deno.jsonc`))&&t.push(`deno`),e.includes(`pyproject.toml`)&&t.push(`uv`),t}get primaryPackageManager(){return this.packageManagers[0]||null}async dependencies(){return await er(this)}async outdatedDependencies(e){return(await Promise.all(Object.values(I).map(t=>t.outdatedDependencies?t.outdatedDependencies(this,e):Promise.resolve([])))).flat()}async deduplicateDependencies(e){return(await Promise.all(Object.values(I).map(t=>t.deduplicateDependencies?t.deduplicateDependencies(this,e):Promise.resolve(null)))).filter(e=>e!==null)}get actions(){return Zn(this)}get services(){return this.config.services||{}}async findFilesByName(e){let t=[],n=async i=>{let a=await(0,r.readdir)(i,{withFileTypes:!0});for(let r of a)r.isDirectory()?r.name!==`node_modules`&&await n(`${i}/${r.name}`):r.name===e&&t.push(`${i}/${r.name}`)};return await n(this.path),t}},nr=class e{primaryWorktree;worktrees;activeWorktree;constructor(e,t){this.primaryWorktree=e,this.worktrees=t,this.activeWorktree=e}static async retrieve(t){let n=Gn(t);if(!n){let n=await tr.retrieve(t,`main`,!0);return new e(n,[n])}let r=n.worktree.primaryPath,i=Wn(t),[a,...o]=await Promise.all([tr.retrieve(r,`main`,!0),...i.map(e=>tr.retrieve(e.path,e.branch,!1))]),s=[a,...o],c=new e(a,s);return c.activeWorktree=s.find(e=>e.path===t)??a,c}worktree(e){return e===`main`?this.primaryWorktree:this.worktrees.find(t=>t.branch===e)??null}get id(){return this.primaryWorktree.id}get slug(){return this.primaryWorktree.slug}get refs(){return this.primaryWorktree.refs}get name(){return this.primaryWorktree.name}get path(){return this.primaryWorktree.path}};const rr=async e=>{let n=An(e).split(`/`),i=[``];for(let e of n){if(e===``){i=i.map(e=>`${e}/`);continue}if(e===`*`){let e=[];for(let n of i){let i=n||`/`;if(await t.n(i))try{let t=await(0,r.readdir)(i,{withFileTypes:!0});for(let r of t)r.isDirectory()&&(r.name.startsWith(`.`)||e.push(`${n}${r.name}`))}catch{}}i=e}else i=i.map(t=>`${t}${e}`);i=i.map(e=>`${e}/`)}let a=[];for(let e of i){let n=e.replace(/\/$/,``);await t.t(n)&&a.push(n)}return a},ir=async e=>{let n=(await q()).projectPaths,r=e?.withConfig??!1,i=await Promise.all(n.map(rr)),a=new Set,o=[];for(let e of i.flat())a.has(e)||(a.add(e),o.push(e));return(await Promise.all(o.map(async e=>r&&!await t.n(`${e}/.denvig.yml`)?null:{slug:Yn(e),path:e}))).filter(e=>e!==null).sort((e,t)=>e.slug.localeCompare(t.slug))},ar=async()=>{let e=await ir({withConfig:!0}),t=new Map;return await Promise.all(e.map(async e=>{let n=await nr.retrieve(e.path);for(let e of n.worktrees)t.set(e.id,{slug:e.slug,path:e.path})})),t},or=`global`,sr=(0,l.createHash)(`sha1`).update(`denvig-global`).digest(`hex`);async function cr(){let e=await q(),t=(0,a.resolve)((0,i.homedir)(),`.denvig`),n=e.services;if(n){let e={};for(let[r,i]of Object.entries(n))i.cwd?e[r]=i:e[r]={...i,cwd:(0,a.resolve)(t,`services`,`${sr}.${r}`,`cwd`)};n=e}return{id:sr,slug:or,name:`Global`,path:(0,i.homedir)(),config:{services:n}}}async function lr(){return new $(await cr())}function ur(e){return e===or}const dr=d.z.object({id:d.z.string(),slug:d.z.string(),name:d.z.string(),path:d.z.string()}),fr=d.z.object({command:d.z.string(),env:d.z.record(d.z.string(),d.z.string()).optional(),envFiles:d.z.array(d.z.string()).optional(),http:d.z.object({port:d.z.number().optional(),domain:d.z.string().optional(),cnames:d.z.array(d.z.string()).optional(),secure:d.z.boolean().optional()}).optional(),keepAlive:d.z.boolean().optional(),startOnBoot:d.z.boolean().optional()}),pr=d.z.object({cwd:d.z.string(),port:d.z.number().int().positive().optional(),domains:d.z.array(d.z.string()).default([]),desiredStatus:d.z.enum([`running`,`stopped`]).default(`running`),project:dr.optional(),serviceName:d.z.string().optional(),config:fr.optional()}),mr=d.z.object({project:d.z.string(),service:d.z.string(),port:d.z.number().int().positive(),defaultService:d.z.boolean().default(!0),secure:d.z.boolean().default(!1),desiredStatus:d.z.enum([`running`,`stopped`]).default(`running`),cert:d.z.string().optional()}),hr=d.z.object({dir:d.z.string(),certPath:d.z.string(),keyPath:d.z.string(),domains:d.z.array(d.z.string()).default([])}),gr=d.z.object({services:d.z.record(d.z.string(),pr).default({}),gatewayRoutes:d.z.record(d.z.string(),mr).default({}),certs:d.z.record(d.z.string(),hr).default({})}),_r=()=>(0,a.resolve)((0,i.homedir)(),`.denvig`,`state.json`),vr=()=>({services:{},gatewayRoutes:{},certs:{}}),Y=(e,t)=>`id:${e}:${t}`,X=async()=>{try{let e=await(0,r.readFile)(_r(),`utf-8`),t=gr.safeParse(JSON.parse(e));return t.success?t.data:vr()}catch{return vr()}},Z=async e=>{let t=_r();await(0,r.mkdir)((0,a.dirname)(t),{recursive:!0});let n=`${t}.${process.pid}.tmp`;await(0,r.writeFile)(n,`${JSON.stringify(e,null,2)}\n`,`utf-8`),await(0,r.rename)(n,t)},yr=async(e,t)=>(await X()).services[Y(e,t)]??null,br=async(e,t,n)=>{let r=await X(),i=Y(e,t),a=r.services[i];r.services[i]={cwd:n.cwd,port:n.port??a?.port,domains:n.domains??a?.domains??[],desiredStatus:n.desiredStatus??a?.desiredStatus??`running`,project:n.project??a?.project,serviceName:n.serviceName??a?.serviceName??t,config:n.config??a?.config},await Z(r)},xr=async(e,t)=>{let n=await X(),r=Y(e,t),i=n.services[r];i&&(n.services[r]={...i,desiredStatus:`stopped`},await Z(n))},Sr=async(e,t)=>{let n=await X(),r=Y(e,t);r in n.services&&(delete n.services[r],await Z(n))},Cr=e=>{let t=new Set;for(let n of Object.values(e.services))n.desiredStatus===`running`&&n.port!==void 0&&t.add(n.port);return t},wr=async e=>(await X()).gatewayRoutes[e]??null,Tr=async(e,t)=>{let n=await X();n.gatewayRoutes[e]=t,await Z(n)},Er=async(e,t)=>{let n=await X(),r=!1;for(let[i,a]of Object.entries(n.gatewayRoutes))a.project===e&&a.service===t&&(n.gatewayRoutes[i]={...a,desiredStatus:`stopped`},r=!0);r&&await Z(n)},Dr=async(e,t)=>{let n=await X(),r=!1;for(let[i,a]of Object.entries(n.gatewayRoutes))a.project===e&&a.service===t&&(delete n.gatewayRoutes[i],r=!0);r&&await Z(n)},Or=async(e,t)=>{let n=await X();n.certs[e]=t,await Z(n)};function kr(){return(0,a.resolve)((0,i.homedir)(),`.denvig`,`gateway`,`html`)}async function Ar(){let e=kr(),t=(0,a.resolve)(e,`errors`);await(0,r.mkdir)(t,{recursive:!0}),await(0,r.writeFile)((0,a.resolve)(e,`index.html`),jr,`utf-8`),await(0,r.writeFile)((0,a.resolve)(t,`404.html`),Mr,`utf-8`),await(0,r.writeFile)((0,a.resolve)(t,`504.html`),Nr,`utf-8`)}const jr=`<!DOCTYPE html>
|
|
18
|
+
<html lang="en">
|
|
19
|
+
<head>
|
|
20
|
+
<meta charset="utf-8">
|
|
21
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
22
|
+
<title>Denvig Gateway</title>
|
|
23
|
+
<style>
|
|
24
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
25
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0a0a0a; color: #e0e0e0; display: flex; align-items: center; justify-content: center; min-height: 100vh; }
|
|
26
|
+
.container { text-align: center; max-width: 480px; padding: 2rem; }
|
|
27
|
+
h1 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.75rem; color: #fff; }
|
|
28
|
+
p { font-size: 0.95rem; line-height: 1.6; color: #888; margin-bottom: 1.5rem; }
|
|
29
|
+
a { color: #6ea4f7; text-decoration: none; }
|
|
30
|
+
a:hover { text-decoration: underline; }
|
|
31
|
+
code { background: #1a1a1a; padding: 0.15rem 0.4rem; border-radius: 4px; font-size: 0.85rem; color: #ccc; }
|
|
32
|
+
</style>
|
|
33
|
+
</head>
|
|
34
|
+
<body>
|
|
35
|
+
<div class="container">
|
|
36
|
+
<h1>Denvig Gateway</h1>
|
|
37
|
+
<p>This nginx server is managed by <a href="https://denvig.com">Denvig</a>.</p>
|
|
38
|
+
<p>Configure services with <code>http.domain</code> in your <code>.denvig.yml</code> to route traffic here.</p>
|
|
39
|
+
</div>
|
|
40
|
+
</body>
|
|
41
|
+
</html>
|
|
42
|
+
`,Mr=`<!DOCTYPE html>
|
|
43
|
+
<html lang="en">
|
|
44
|
+
<head>
|
|
45
|
+
<meta charset="utf-8">
|
|
46
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
47
|
+
<title>404 - Not Found</title>
|
|
48
|
+
<style>
|
|
49
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
50
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0a0a0a; color: #e0e0e0; display: flex; align-items: center; justify-content: center; min-height: 100vh; }
|
|
51
|
+
.container { text-align: center; max-width: 480px; padding: 2rem; }
|
|
52
|
+
.code { font-size: 3rem; font-weight: 700; color: #555; margin-bottom: 0.5rem; }
|
|
53
|
+
h1 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.75rem; color: #fff; }
|
|
54
|
+
p { font-size: 0.95rem; line-height: 1.6; color: #888; margin-bottom: 1rem; }
|
|
55
|
+
a { color: #6ea4f7; text-decoration: none; }
|
|
56
|
+
a:hover { text-decoration: underline; }
|
|
57
|
+
code { background: #1a1a1a; padding: 0.15rem 0.4rem; border-radius: 4px; font-size: 0.85rem; color: #ccc; }
|
|
58
|
+
</style>
|
|
59
|
+
</head>
|
|
60
|
+
<body>
|
|
61
|
+
<div class="container">
|
|
62
|
+
<div class="code">404</div>
|
|
63
|
+
<h1>Service Not Found</h1>
|
|
64
|
+
<p>No service is configured for this domain. The project may not exist or the domain is not set up in <code>.denvig.yml</code>.</p>
|
|
65
|
+
<p>Check your configuration with <code>denvig gateway status</code></p>
|
|
66
|
+
<p><a href="https://denvig.com">denvig.com</a></p>
|
|
67
|
+
</div>
|
|
68
|
+
</body>
|
|
69
|
+
</html>
|
|
70
|
+
`,Nr=`<!DOCTYPE html>
|
|
71
|
+
<html lang="en">
|
|
72
|
+
<head>
|
|
73
|
+
<meta charset="utf-8">
|
|
74
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
75
|
+
<title>504 - Service Unavailable</title>
|
|
76
|
+
<style>
|
|
77
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
78
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0a0a0a; color: #e0e0e0; display: flex; align-items: center; justify-content: center; min-height: 100vh; }
|
|
79
|
+
.container { text-align: center; max-width: 480px; padding: 2rem; }
|
|
80
|
+
.code { font-size: 3rem; font-weight: 700; color: #555; margin-bottom: 0.5rem; }
|
|
81
|
+
h1 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.75rem; color: #fff; }
|
|
82
|
+
p { font-size: 0.95rem; line-height: 1.6; color: #888; margin-bottom: 1rem; }
|
|
83
|
+
a { color: #6ea4f7; text-decoration: none; }
|
|
84
|
+
a:hover { text-decoration: underline; }
|
|
85
|
+
code { background: #1a1a1a; padding: 0.15rem 0.4rem; border-radius: 4px; font-size: 0.85rem; color: #ccc; }
|
|
86
|
+
</style>
|
|
87
|
+
</head>
|
|
88
|
+
<body>
|
|
89
|
+
<div class="container">
|
|
90
|
+
<div class="code">504</div>
|
|
91
|
+
<h1>Service Unavailable</h1>
|
|
92
|
+
<p>This service is configured but does not appear to be running. Start it with <code>denvig services start</code>.</p>
|
|
93
|
+
<p>Check service status with <code>denvig services</code></p>
|
|
94
|
+
<p><a href="https://denvig.com">denvig.com</a></p>
|
|
95
|
+
</div>
|
|
96
|
+
</body>
|
|
97
|
+
</html>
|
|
98
|
+
`,Pr=(0,c.promisify)(n.exec);function Fr(e){let{projectId:t,projectPath:n,projectSlug:r,serviceName:i,port:a,domain:o,cnames:s,sslCertPath:c,sslKeyPath:l}=e,u=`denvig-${t}--${i}`,d=[o,...s||[]].join(` `),f=!!(c&&l),p=f?`
|
|
99
|
+
ssl_certificate ${c};
|
|
100
|
+
ssl_certificate_key ${l};
|
|
101
|
+
ssl_protocols TLSv1.2 TLSv1.3;
|
|
102
|
+
ssl_ciphers HIGH:!aNULL:!MD5;`:``;return`# denvig:
|
|
103
|
+
# slug: ${r}
|
|
104
|
+
# path: ${n}
|
|
105
|
+
# service: ${i}
|
|
106
|
+
upstream ${u} { server 127.0.0.1:${a} max_fails=0 fail_timeout=30; }
|
|
107
|
+
server {
|
|
108
|
+
${f?` listen 80;
|
|
109
|
+
listen 443 ssl;
|
|
110
|
+
http2 on;`:` listen 80;`}
|
|
111
|
+
server_name ${d};
|
|
112
|
+
root ${n}/public;
|
|
113
|
+
index index.html;
|
|
114
|
+
client_max_body_size 100M;
|
|
115
|
+
${p}
|
|
116
|
+
|
|
117
|
+
error_page 502 503 504 /denvig-errors/504.html;
|
|
118
|
+
location /denvig-errors/ {
|
|
119
|
+
alias ${kr()}/errors/;
|
|
120
|
+
internal;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
location / {
|
|
124
|
+
proxy_pass http://${u};
|
|
125
|
+
proxy_set_header Host $host;
|
|
126
|
+
proxy_set_header X-Forwarded-Host $host;
|
|
127
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
128
|
+
proxy_redirect off;
|
|
129
|
+
proxy_buffering off;
|
|
130
|
+
|
|
131
|
+
proxy_http_version 1.1;
|
|
132
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
133
|
+
proxy_set_header Connection "upgrade";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
`}function Ir(e){return(0,a.resolve)(e,`..`,`nginx.conf`)}function Lr(e){let t=kr();return`# Managed by denvig — do not edit manually
|
|
137
|
+
# https://denvig.com
|
|
138
|
+
|
|
139
|
+
worker_processes 4;
|
|
140
|
+
|
|
141
|
+
events {
|
|
142
|
+
worker_connections 1024;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
http {
|
|
146
|
+
include ${(0,a.resolve)(e,`..`)}/mime.types;
|
|
147
|
+
default_type application/octet-stream;
|
|
148
|
+
|
|
149
|
+
sendfile on;
|
|
150
|
+
keepalive_timeout 65;
|
|
151
|
+
|
|
152
|
+
server {
|
|
153
|
+
listen 80 default_server;
|
|
154
|
+
server_name _;
|
|
155
|
+
|
|
156
|
+
root ${t};
|
|
157
|
+
index index.html;
|
|
158
|
+
|
|
159
|
+
error_page 404 /errors/404.html;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
include ${e}/*;
|
|
163
|
+
}
|
|
164
|
+
`}async function Rr(e){try{return await(0,r.writeFile)(Ir(e),Lr(e),`utf-8`),{success:!0}}catch(e){return{success:!1,message:`Failed to write nginx.conf: ${e instanceof Error?e.message:`Unknown error`}`}}}function zr(e,t,n){return(0,a.resolve)(n,`denvig.${e}.${t}.conf`)}async function Br(e,t){try{let n=zr(e.projectId,e.serviceName,t);return await(0,r.mkdir)((0,a.dirname)(n),{recursive:!0}),await(0,r.writeFile)(n,Fr(e),`utf-8`),{success:!0}}catch(e){return{success:!1,message:`Failed to write nginx config: ${e instanceof Error?e.message:`Unknown error`}`}}}async function Vr(){try{return await Pr(`/opt/homebrew/bin/nginx -s reload`),{success:!0}}catch(e){return{success:!1,message:`Failed to reload nginx: ${e instanceof Error?e.message:`Unknown error`}`}}}async function Hr(e){try{let t=(await(0,r.readdir)(e)).filter(e=>e.startsWith(`denvig.`)&&e.endsWith(`.conf`));return await Promise.all(t.map(t=>(0,r.rm)((0,a.resolve)(e,t),{force:!0}))),{success:!0,removed:t}}catch(e){return{success:!1,removed:[],message:`Failed to remove nginx configs: ${e instanceof Error?e.message:`Unknown error`}`}}}async function Ur(){let e=(await q()).experimental?.gateway;if(!e?.enabled)return null;let t=e.configsPath;await Ar();let n=await Rr(t);if(!n.success)return{success:!1,removed:[],services:[],nginxReload:!1,message:n.message||`Failed to write nginx.conf`};let r=await Hr(t);if(!r.success)return{success:!1,removed:[],services:[],nginxReload:!1,message:r.message||`Failed to remove existing configs`};let i=await ar(),a=await cr();i.set(a.id,{slug:a.slug,path:a.path});let o=await X(),s=new Map;for(let[e,t]of Object.entries(o.gatewayRoutes)){if(t.desiredStatus!==`running`)continue;let n=`${t.project}.${t.service}`,r=s.get(n);r?(r.domains.push(e),!r.certKey&&t.cert&&(r.certKey=t.cert)):s.set(n,{projectId:t.project,serviceName:t.service,port:t.port,secure:t.secure,domains:[e],certKey:t.cert})}let c=[];for(let e of s.values()){let n=i.get(e.projectId);if(!n)continue;let[r,...a]=e.domains,s=e.secure,l,u,d=`not_configured`,f,p;if(s){let t=e.certKey?o.certs[e.certKey]:void 0;t?(l=t.certPath,u=t.keyPath,d=`valid`,f=t.dir):(d=`missing`,p=e.certKey?`cert "${e.certKey}" referenced by route is not in state.certs`:`route has no cert reference; restart the service to refresh state.certs`)}let m={projectSlug:n.slug,serviceName:e.serviceName,domain:r,cnames:a,port:e.port,certStatus:d,certDir:f,certMessage:p,configStatus:`written`},h=await Br({projectId:e.projectId,projectPath:n.path,projectSlug:n.slug,serviceName:e.serviceName,port:e.port,domain:r,cnames:a,sslCertPath:l,sslKeyPath:u},t);h.success||(m.configStatus=`error`,m.configMessage=h.message),c.push(m)}let l=await Vr(),u=c.some(e=>e.configStatus===`error`||e.certStatus===`missing`);return{success:!u,removed:r.removed,services:c,nginxReload:l.success,nginxReloadMessage:l.message,message:u?`Some services have errors or missing certificates`:`Gateway configured successfully`}}const Wr=[`.env.development`,`.env.local`];function Gr(e){let t={},n=e.split(`
|
|
165
|
+
`);for(let e=0;e<n.length;e++){let r=n[e].trim();if(!r||r.startsWith(`#`))continue;let i=r.indexOf(`=`);if(i===-1)continue;let a=r.slice(0,i).trim(),o=r.slice(i+1).trim(),s=o.startsWith(`"`),c=o.startsWith(`'`);if(s||c){let e=s?`"`:`'`,t=o.indexOf(e,1);if(t!==-1)o=o.slice(1,t);else{let e=o.indexOf(`#`);e!==-1&&(o=o.slice(0,e).trim())}}else{let e=o.indexOf(`#`);e!==-1&&(o=o.slice(0,e).trim())}a&&(t[a]=o)}return t}async function Kr(e){try{return Gr(await(0,r.readFile)(e,`utf-8`))}catch(t){let n=t;throw n.code===`ENOENT`?Error(`Environment file not found: ${e}`):Error(`Failed to read environment file: ${n.message||`Unknown error`}`)}}async function qr(e,t){let n={},i=t?.skipMissing??!1;for(let t of e){if(i)try{await(0,r.access)(t)}catch{continue}let e=await Kr(t);Object.assign(n,e)}return n}function Q(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`).replace(/'/g,`'`)}function Jr(e){return`{ ${e.trim()}; } 2>&1 | while IFS= read -r line; do printf '[%s] %s\\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$line"; done`}function Yr(e){return e.replace(/'/g,`'\\''`)}function Xr(e){let t=Jr(e.command);return`#!/bin/bash
|
|
166
|
+
#
|
|
167
|
+
# Denvig service wrapper
|
|
168
|
+
# Service: ${e.serviceName}
|
|
169
|
+
# Project: ${e.projectSlug}
|
|
170
|
+
# Path: ${e.projectPath}
|
|
171
|
+
# Command: ${e.command}
|
|
172
|
+
# Workdir: ${e.workingDirectory}
|
|
173
|
+
#
|
|
174
|
+
exec /bin/zsh -l -c '${Yr(t)}'
|
|
175
|
+
`}function Zr(e){let{label:t,programPath:n,workingDirectory:r,environmentVariables:i={},standardOutPath:a,keepAlive:o,runAtLoad:s}=e,c=Object.entries(i).map(([e,t])=>` <key>${Q(e)}</key>
|
|
176
|
+
<string>${Q(t)}</string>`).join(`
|
|
177
|
+
`);return`<?xml version="1.0" encoding="UTF-8"?>
|
|
178
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
179
|
+
<plist version="1.0">
|
|
180
|
+
<dict>
|
|
181
|
+
<key>Label</key>
|
|
182
|
+
<string>${Q(t)}</string>
|
|
183
|
+
|
|
184
|
+
<key>ProgramArguments</key>
|
|
185
|
+
<array>
|
|
186
|
+
<string>${Q(n)}</string>
|
|
187
|
+
</array>
|
|
188
|
+
|
|
189
|
+
<key>WorkingDirectory</key>
|
|
190
|
+
<string>${Q(r)}</string>
|
|
191
|
+
|
|
192
|
+
<key>EnvironmentVariables</key>
|
|
193
|
+
<dict>
|
|
194
|
+
${c}
|
|
195
|
+
</dict>
|
|
196
|
+
|
|
197
|
+
<key>StandardOutPath</key>
|
|
198
|
+
<string>${Q(a)}</string>
|
|
199
|
+
|
|
200
|
+
<key>KeepAlive</key>
|
|
201
|
+
<${o?`true`:`false`}/>
|
|
202
|
+
|
|
203
|
+
<key>RunAtLoad</key>
|
|
204
|
+
<${s?`true`:`false`}/>
|
|
205
|
+
</dict>
|
|
206
|
+
</plist>
|
|
207
|
+
`}const Qr={min:8e3,max:9999},$r=e=>new Promise(t=>{let n=(0,f.createServer)();n.unref(),n.once(`error`,e=>{t(e.code===`EADDRINUSE`)}),n.once(`listening`,()=>{n.close(()=>t(!1))}),n.listen(e)}),ei=async e=>{let t=e?.range??Qr,n=await X(),r=new Set([...Cr(n),...e?.excludePorts??[]]),i=async e=>r.has(e)?!1:!await $r(e);if(e?.preferredPort&&await i(e.preferredPort))return e.preferredPort;let a=t.max-t.min+1,o=Math.min(a,200);for(let e=0;e<o;e++){let e=t.min+Math.floor(Math.random()*a);if(await i(e))return e;r.add(e)}return null};var $=class{project;constructor(e){this.project=e}async listServices(){let e=this.project.config.services||{};return Object.entries(e).map(([e,t])=>({name:e,cwd:t.cwd||`.`,command:t.command,http:t.http,startOnBoot:t.startOnBoot}))}async buildServiceEnvironment(e,t){let n=this.getServiceConfig(e);if(!n)return{success:!1,message:`Service "${e}" not found in configuration`};let r=this.resolveServiceCwd(n),i={DENVIG_PROJECT:this.project.slug,DENVIG_SERVICE:e},o=n.envFiles??Wr;if(o.length>0)try{let e=await qr(o.map(e=>(0,a.resolve)(r,e)),{skipMissing:!0});Object.assign(i,e)}catch(e){return{success:!1,message:`Failed to load environment file: ${e instanceof Error?e.message:`Unknown error`}`}}n.env&&Object.assign(i,n.env);let s=t?.port??n.http?.port;return s!==void 0&&(i.PORT=s.toString()),{success:!0,env:i}}async resolveServicePort(e,t){let n=this.getServiceConfig(e);if(!n)return{success:!1,message:`Service "${e}" not found in configuration`};let r=n.http?.port,i=await yr(this.project.id,e);if(t?.forceRandom){let e=await ei({preferredPort:i?.port});return{success:!0,port:e??void 0,source:e===null?`none`:`allocated`,conflict:!1,configPort:r}}if(i?.port!==void 0)return{success:!0,port:i.port,source:`state`,conflict:!1,configPort:r};if(r!==void 0){if(!await $r(r))return{success:!0,port:r,source:`config`,conflict:!1,configPort:r};let e=await ei();return{success:!0,port:e??void 0,source:e===null?`none`:`allocated`,conflict:!0,configPort:r}}let a=await ei();return{success:!0,port:a??void 0,source:a===null?`none`:`allocated`,conflict:!1,configPort:r}}async startService(e,t){let n=this.getServiceConfig(e);if(!n)return{name:e,success:!1,message:`Service "${e}" not found in configuration`};let i=t?.port;if(!t?.portResolved){let t=await this.resolveServicePort(e);if(!t.success)return{name:e,success:!1,message:t.message};if(t.conflict&&t.source===`none`)return{name:e,success:!1,message:`Port ${t.configPort} is in use and no free port could be allocated`};i=t.port}let o=await this.buildServiceEnvironment(e,{port:i});if(!o.success)return{name:e,success:!1,message:o.message};let s=this.getServiceLabel(e),c=await z.print(s),l=c!==null,u=c!==null&&c.pid!==void 0&&c.state===`running`,d=n.http?.domain?[n.http.domain,...n.http.cnames??[]]:[];if(await br(this.project.id,e,{cwd:this.resolveServiceCwd(n),port:i,domains:d,desiredStatus:`running`,project:{id:this.project.id,slug:this.project.slug,name:this.project.name,path:this.project.path},serviceName:e,config:{command:n.command,env:n.env,envFiles:n.envFiles,http:n.http,keepAlive:n.keepAlive,startOnBoot:n.startOnBoot}}),i!==void 0&&d.length>0){let r=n.http?.secure??!1,o;if(r){let e=await K(d[0]);if(e){let t=await xn(e);t&&(o=(0,a.basename)(e),await Or(o,{dir:e,certPath:t.sslCertPath,keyPath:t.sslKeyPath,domains:d}))}}for(let n of d){let a=await wr(n),s=a?.project===this.project.id&&a?.service===e,c=a!==null&&!s&&a.desiredStatus===`stopped`;!a||s||c?await Tr(n,{project:this.project.id,service:e,port:i,secure:r,defaultService:s?a?.defaultService??!0:!0,desiredStatus:`running`,cert:o}):t?.claimDomain===!0&&await Tr(n,{project:this.project.id,service:e,port:i,secure:r,defaultService:!1,desiredStatus:`running`,cert:o})}}await this.ensureDenvigDirectories();let f=await this.createLogFile(e),p=this.getPlistPath(e),m=this.resolveServiceCwd(n);await(0,r.mkdir)(m,{recursive:!0});let h=this.getServiceScriptPath(e),g=Xr({command:n.command,serviceName:e,projectPath:this.project.path,projectSlug:this.project.slug,workingDirectory:m}),_=null;try{_=await(0,r.readFile)(h,`utf-8`)}catch{}_!==g&&(await(0,r.writeFile)(h,g,`utf-8`),await(0,r.chmod)(h,493));let v=Zr({label:s,programPath:h,workingDirectory:m,environmentVariables:o.env,standardOutPath:this.getStableLogPath(e),keepAlive:n.keepAlive??!0,runAtLoad:n.startOnBoot??!1}),y=null;try{y=await(0,r.readFile)(p,`utf-8`)}catch{}let b=y!==v;if(b&&await(0,r.writeFile)(p,v,`utf-8`),await z.enable(s),!l){let t=await z.bootstrap(p);if(!t.success)return{name:e,success:!1,message:`Failed to bootstrap service: ${t.output}`}}else if(b||t?.reviveIfNotRunning!==!1&&!u){let t=await z.bootout(s);if(!t.success)return{name:e,success:!1,message:`Failed to bootout service: ${t.output}`};await new Promise(e=>setTimeout(e,1e3));let n=await z.bootstrap(p);if(!n.success)return{name:e,success:!1,message:`Failed to bootstrap service: ${n.output}`}}else return{name:e,success:!0,message:`Service already running with current config`};try{await(0,r.appendFile)(f,`[${new Date().toISOString()}] Service Started\n`,`utf-8`)}catch{}return{name:e,success:!0,message:`Service started successfully`}}async stopService(e){let t=this.getServiceConfig(e);if(!t)return{name:e,success:!1,message:`Service "${e}" not found in configuration`};let n=this.getServiceLabel(e);if(!await this.isServiceBootstrapped(e))return{name:e,success:!1,message:`Service "${e}" is not running`};let i=!1;if(t.startOnBoot){let t=await z.stop(n);if(!t.success)return{name:e,success:!1,message:`Failed to stop service: ${t.output}`}}else{let t=await z.bootout(n);if(!t.success)return{name:e,success:!1,message:`Failed to stop service: ${t.output}`};await z.disable(n),i=!0}try{let t=new Date().toISOString();await(0,r.appendFile)(this.getLogPath(e),`[${t}] Service Stopped\n`,`utf-8`)}catch{}return await xr(this.project.id,e),await Er(this.project.id,e),i&&await this.reconfigureGateway(),{name:e,success:!0,message:`Service stopped successfully`}}async restartService(e,t){if(!this.getServiceConfig(e))return{name:e,success:!1,message:`Service "${e}" not found in configuration`};if(await this.isServiceBootstrapped(e)){let t=await this.stopService(e);if(!t.success)return t}return await this.startService(e,t)}async getServiceStatus(e){let t=this.getServiceConfig(e);if(!t)return null;let n=this.getServiceLabel(e),r=await z.print(n);if(!r)return{name:e,running:!1,command:t.command,cwd:this.resolveServiceCwd(t),logPath:this.getLogPath(e)};let i=await this.getRecentLogs(e,20);return{name:e,running:r.state===`running`,pid:r.pid,command:t.command,cwd:this.resolveServiceCwd(t),logs:i,logPath:this.getLogPath(e),lastExitCode:r.lastExitCode}}async startAll(){let e=this.project.config.services||{},t=Object.keys(e);return await Promise.all(t.map(e=>this.startService(e)))}async stopAll(){let e=this.project.config.services||{},t=Object.keys(e),n=(await Promise.all(t.map(async e=>({name:e,isBootstrapped:await this.isServiceBootstrapped(e)})))).filter(e=>e.isBootstrapped).map(e=>e.name);return await Promise.all(n.map(e=>this.stopService(e)))}async restartAll(){let e=this.project.config.services||{},t=Object.keys(e),n=(await Promise.all(t.map(async e=>({name:e,isBootstrapped:await this.isServiceBootstrapped(e)})))).filter(e=>e.isBootstrapped).map(e=>e.name);return await Promise.all(n.map(e=>this.restartService(e)))}async teardownAll(e){let t=[],n=`denvig.${this.project.id}.`,o=[],s=await z.list(n);for(let e of s){let r=await z.bootout(e.label),i=e.label.replace(n,``);r.success?(o.push(e.label),t.push({name:i,success:!0,message:`Service removed from launchctl`})):t.push({name:i,success:!1,message:`Failed to bootout: ${r.output}`})}let c=(0,a.resolve)((0,i.homedir)(),`Library`,`LaunchAgents`);if(await Promise.all(o.map(async e=>{try{await(0,r.unlink)((0,a.resolve)(c,`${e}.plist`))}catch{}})),e?.removeLogs&&o.length>0){let e=this.getDenvigHomeDir(),t=(0,a.resolve)(e,`logs`),n=o.map(e=>e.replace(`denvig.`,``));await Promise.all(n.flatMap(n=>[(0,r.rm)((0,a.resolve)(e,`services`,n),{recursive:!0,force:!0}).catch(()=>{}),(0,r.unlink)((0,a.resolve)(t,`${n}.log`)).catch(()=>{}),(0,r.unlink)((0,a.resolve)(t,`${n}.error.log`)).catch(()=>{})]))}return await Promise.all(o.flatMap(e=>{let t=e.replace(n,``);return[Sr(this.project.id,t),Dr(this.project.id,t)]})),await this.reconfigureGateway(),t}async isServiceBootstrapped(e){let t=this.getServiceLabel(e);return await z.print(t)!==null}normalizeForLabel(e){return e.replace(/\//g,`__`).replace(/:/g,`-`).replace(/[^a-zA-Z0-9_.-]/g,`_`)}getServiceLabel(e){let t=this.normalizeForLabel(e);return`denvig.${this.project.id}.${t}`}getDenvigHomeDir(){return(0,a.resolve)((0,i.homedir)(),`.denvig`)}getPlistPath(e){let t=this.getServiceLabel(e);return(0,a.resolve)((0,i.homedir)(),`Library`,`LaunchAgents`,`${t}.plist`)}getServiceDir(e){let t=this.normalizeForLabel(e),n=`${this.project.id}.${t}`;return(0,a.resolve)(this.getDenvigHomeDir(),`services`,n)}getServiceLogDir(e){return(0,a.resolve)(this.getServiceDir(e),`logs`)}getServiceScriptPath(e){let t=this.normalizeForLabel(e),n=this.project.slug,r=n.startsWith(`github:`)?`${n.replace(`github:`,``).replace(`/`,`-`)}-`:``;return(0,a.resolve)(this.getServiceDir(e),`denvig-${r}${t}`)}getStableLogPath(e){return(0,a.resolve)(this.getServiceLogDir(e),`latest.log`)}getLogPath(e,t){let n=(0,i.hostname)();return(0,a.resolve)(this.getServiceLogDir(e),`latest.${n}.log`)}async createLogFile(e){let t=this.getServiceLogDir(e);await(0,r.mkdir)(t,{recursive:!0});let n=`${Math.floor(Date.now()/1e3)}.log`,i=(0,a.resolve)(t,n);await(0,r.writeFile)(i,``,`utf-8`);let o=this.getStableLogPath(e),s=this.getLogPath(e);return await Promise.all([o,s].map(async e=>{try{await(0,r.unlink)(e)}catch{}await(0,r.symlink)(n,e)})),i}async ensureDenvigDirectories(){await(0,r.mkdir)((0,a.resolve)(this.getDenvigHomeDir(),`logs`),{recursive:!0})}async getRecentLogs(e,t){try{return(await(0,r.readFile)(this.getLogPath(e),`utf-8`)).trim().split(`
|
|
208
|
+
`).slice(-t)}catch{return[]}}resolveServiceCwd(e){return(0,a.resolve)(this.project.path,e.cwd||`.`)}getServiceConfig(e){return this.project.config.services?.[e]}async reconfigureGateway(){let e=await Ur();e&&!e.success&&console.warn(`[gateway] ${e.message}`)}async getServiceUrl(e){let t=this.getServiceConfig(e);if(!t)return null;if(t.http?.domain){let n=await wr(t.http.domain);if(n?.project===this.project.id&&n?.service===e&&n?.desiredStatus===`running`)return`${t.http.secure?`https`:`http`}://${t.http.domain}`}return await this.getServiceLocalUrl(e)}async getServiceLocalUrl(e){let t=await this.getEffectivePort(e);return t===void 0?null:`http://localhost:${t}`}async getEffectivePort(e){let t=await yr(this.project.id,e);return t?.port===void 0?this.getServiceConfig(e)?.http?.port:t.port}async plistExists(e){try{return await(0,r.access)(this.getPlistPath(e)),!0}catch{return!1}}async getServiceResponse(e,t){let n=this.getServiceConfig(e);if(!n)return null;let r=this.getServiceLabel(e),i=`stopped`,o=null,s=null;if(t?.launchctlList){let e=t.launchctlList.find(e=>e.label===r);e&&(o=e.pid===`-`?null:e.pid,s=e.status,i=o===null?s===0?`stopped`:`error`:s===0?`running`:`error`)}else if(await this.plistExists(e)){let e=await z.print(r);e&&(o=e.pid??null,s=e.lastExitCode??null,e.state===`running`&&(i=s!==null&&s!==0?`error`:`running`))}let c=await this.getEffectivePort(e),l={name:e,project:{id:this.project.id,slug:this.project.slug,name:this.project.name,path:this.project.path},status:i,pid:o,url:await this.getServiceUrl(e),localUrl:await this.getServiceLocalUrl(e),port:c??null,configPort:n.http?.port??null,command:n.command,cwd:this.resolveServiceCwd(n),logPath:this.getLogPath(e),envFiles:(n.envFiles??Wr).map(e=>(0,a.resolve)(this.resolveServiceCwd(n),e)),lastExitCode:s};return t?.includeLogs&&(l.logs=await this.getRecentLogs(e,t.logLines??20)),l}};async function ti(e){let t=[],n=[],o=await z.list(`denvig.`);for(let e of o){let r=await z.bootout(e.label);r.success?(n.push(e.label),t.push({name:e.label,success:!0,message:`Service removed from launchctl`})):t.push({name:e.label,success:!1,message:`Failed to bootout: ${r.output}`})}let s=(0,a.resolve)((0,i.homedir)(),`Library`,`LaunchAgents`);try{let e=(await(0,r.readdir)(s)).filter(e=>e.startsWith(`denvig.`)&&e.endsWith(`.plist`));await Promise.all(e.map(async e=>{try{await(0,r.unlink)((0,a.resolve)(s,e))}catch{}}))}catch{}if(e?.removeLogs){let e=(0,a.resolve)((0,i.homedir)(),`.denvig`),t=(0,a.resolve)(e,`logs`);try{let e=await(0,r.readdir)(t);await Promise.all(e.map(async e=>{try{await(0,r.unlink)((0,a.resolve)(t,e))}catch{}}))}catch{}let n=(0,a.resolve)(e,`services`);try{let e=await(0,r.readdir)(n);await Promise.all(e.filter(e=>e.startsWith(`denvig.`)||e.includes(`.`)).map(async e=>{try{await(0,r.rm)((0,a.resolve)(n,e,`logs`),{recursive:!0,force:!0})}catch{}}))}catch{}}try{await(0,r.writeFile)((0,a.resolve)((0,i.homedir)(),`.denvig`,`state.json`),`${JSON.stringify({services:{},gatewayRoutes:{}},null,2)}\n`,`utf-8`)}catch{}return{success:!0,services:t,logsRemoved:e?.removeLogs??!1}}async function ni(e,t){let n=e.activeWorktree,r=await new $(n).teardownAll({removeLogs:t?.removeLogs});return{success:!0,project:n.slug,services:r,logsRemoved:t?.removeLogs??!1}}Object.defineProperty(exports,"$",{enumerable:!0,get:function(){return rt}}),Object.defineProperty(exports,"A",{enumerable:!0,get:function(){return xn}}),Object.defineProperty(exports,"B",{enumerable:!0,get:function(){return nn}}),Object.defineProperty(exports,"C",{enumerable:!0,get:function(){return In}}),Object.defineProperty(exports,"D",{enumerable:!0,get:function(){return Dn}}),Object.defineProperty(exports,"E",{enumerable:!0,get:function(){return q}}),Object.defineProperty(exports,"F",{enumerable:!0,get:function(){return W}}),Object.defineProperty(exports,"G",{enumerable:!0,get:function(){return $t}}),Object.defineProperty(exports,"H",{enumerable:!0,get:function(){return un}}),Object.defineProperty(exports,"I",{enumerable:!0,get:function(){return Qt}}),Object.defineProperty(exports,"J",{enumerable:!0,get:function(){return sn}}),Object.defineProperty(exports,"K",{enumerable:!0,get:function(){return an}}),Object.defineProperty(exports,"L",{enumerable:!0,get:function(){return on}}),Object.defineProperty(exports,"M",{enumerable:!0,get:function(){return hn}}),Object.defineProperty(exports,"N",{enumerable:!0,get:function(){return en}}),Object.defineProperty(exports,"O",{enumerable:!0,get:function(){return K}}),Object.defineProperty(exports,"P",{enumerable:!0,get:function(){return tn}}),Object.defineProperty(exports,"Q",{enumerable:!0,get:function(){return yt}}),Object.defineProperty(exports,"R",{enumerable:!0,get:function(){return pn}}),Object.defineProperty(exports,"S",{enumerable:!0,get:function(){return Bn}}),Object.defineProperty(exports,"T",{enumerable:!0,get:function(){return An}}),Object.defineProperty(exports,"U",{enumerable:!0,get:function(){return dn}}),Object.defineProperty(exports,"V",{enumerable:!0,get:function(){return ln}}),Object.defineProperty(exports,"W",{enumerable:!0,get:function(){return fn}}),Object.defineProperty(exports,"X",{enumerable:!0,get:function(){return z}}),Object.defineProperty(exports,"Y",{enumerable:!0,get:function(){return cn}}),Object.defineProperty(exports,"Z",{enumerable:!0,get:function(){return I}}),Object.defineProperty(exports,"_",{enumerable:!0,get:function(){return Xn}}),Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return Ir}}),Object.defineProperty(exports,"at",{enumerable:!0,get:function(){return ie}}),Object.defineProperty(exports,"b",{enumerable:!0,get:function(){return Rn}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return X}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return cr}}),Object.defineProperty(exports,"et",{enumerable:!0,get:function(){return Ke}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return lr}}),Object.defineProperty(exports,"g",{enumerable:!0,get:function(){return nr}}),Object.defineProperty(exports,"h",{enumerable:!0,get:function(){return ar}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return Ur}}),Object.defineProperty(exports,"it",{enumerable:!0,get:function(){return re}}),Object.defineProperty(exports,"j",{enumerable:!0,get:function(){return gn}}),Object.defineProperty(exports,"k",{enumerable:!0,get:function(){return bn}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return Dr}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return ir}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return ni}}),Object.defineProperty(exports,"nt",{enumerable:!0,get:function(){return xe}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return zr}}),Object.defineProperty(exports,"ot",{enumerable:!0,get:function(){return ne}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return ur}}),Object.defineProperty(exports,"q",{enumerable:!0,get:function(){return rn}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return $}}),Object.defineProperty(exports,"rt",{enumerable:!0,get:function(){return de}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return wr}}),Object.defineProperty(exports,"st",{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return ti}}),Object.defineProperty(exports,"tt",{enumerable:!0,get:function(){return Ve}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return Sr}}),Object.defineProperty(exports,"v",{enumerable:!0,get:function(){return Un}}),Object.defineProperty(exports,"w",{enumerable:!0,get:function(){return J}}),Object.defineProperty(exports,"x",{enumerable:!0,get:function(){return zn}}),Object.defineProperty(exports,"y",{enumerable:!0,get:function(){return Ln}}),Object.defineProperty(exports,"z",{enumerable:!0,get:function(){return H}});
|
package/dist/testing.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./chunk-CMqjfN_6.cjs"),t=require("./project-BqMRVXi0.cjs"),n=require("./teardown-DypXa0Wy.cjs");let r=require("node:fs");r=e.t(r,1);const i=(e={})=>{typeof e==`string`&&(e={slug:e});let t=e.slug??`github:owner/repo`,r=e.name??t.split(`/`).pop()??`test-project`,i=e.path??`/tmp/test-project`,a=n._(i),o=e.config??{name:r,$sources:[]},s={id:a,slug:t,name:r,path:i,config:o,isPrimary:!0,branch:`main`,refs:[],rootFiles:[]};return{id:a,slug:t,name:r,path:i,config:o,primaryWorktree:s,activeWorktree:s,worktrees:[s],worktree:e=>e===`main`?s:null}},a=(e={})=>{let n=i(e);return new t.t(n,{client:`test`,cwd:n.path})},o=e=>({path:e,rootFiles:r.default.readdirSync(e),async findFilesByName(t){let n=[],i=e=>{let a=r.default.readdirSync(e,{withFileTypes:!0});for(let r of a)r.isDirectory()?r.name!==`node_modules`&&i(`${e}/${r.name}`):r.name===t&&n.push(`${e}/${r.name}`)};return i(e),n}});exports.createMockInternalProject=i,exports.createMockProject=a,exports.createMockProjectFromPath=o;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { l as Worktree, y as DenvigProject } from "./teardown-BuHyVdhH.js";
|
|
2
|
+
import { t as DenvigProject$1 } from "./project-DmYu4L1C.js";
|
|
3
|
+
|
|
4
|
+
//#region src/test/mock.d.ts
|
|
5
|
+
type MockProjectOptions = {
|
|
6
|
+
slug?: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
path?: string;
|
|
9
|
+
config?: Worktree['config'];
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Create a mock internal `DenvigProject` for SDK-level tests.
|
|
13
|
+
*
|
|
14
|
+
* The returned mock is backed by a single primary {@link Worktree} (exposed as
|
|
15
|
+
* `activeWorktree`/`primaryWorktree`) and also carries `config` at the top
|
|
16
|
+
* level so it satisfies `ServiceManagerProject` for service tests.
|
|
17
|
+
*/
|
|
18
|
+
declare const createMockInternalProject: (options?: MockProjectOptions | string) => DenvigProject & {
|
|
19
|
+
config: Worktree["config"];
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Create a mock public {@link DenvigProject} for command/SDK-consumer tests.
|
|
23
|
+
* Wraps a mock internal project so the chained resource API is available.
|
|
24
|
+
*/
|
|
25
|
+
declare const createMockProject: (options?: MockProjectOptions | string) => DenvigProject$1;
|
|
26
|
+
/**
|
|
27
|
+
* Create a mock Worktree that reads from a real directory.
|
|
28
|
+
* Use this when tests need actual filesystem access (e.g., plugin tests).
|
|
29
|
+
*/
|
|
30
|
+
declare const createMockProjectFromPath: (projectPath: string) => Worktree;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { MockProjectOptions, createMockInternalProject, createMockProject, createMockProjectFromPath };
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./project-BA4nj7bB.js";import{_ as t}from"./teardown-DgjT-aE7.js";import n from"node:fs";const r=(e={})=>{typeof e==`string`&&(e={slug:e});let n=e.slug??`github:owner/repo`,r=e.name??n.split(`/`).pop()??`test-project`,i=e.path??`/tmp/test-project`,a=t(i),o=e.config??{name:r,$sources:[]},s={id:a,slug:n,name:r,path:i,config:o,isPrimary:!0,branch:`main`,refs:[],rootFiles:[]};return{id:a,slug:n,name:r,path:i,config:o,primaryWorktree:s,activeWorktree:s,worktrees:[s],worktree:e=>e===`main`?s:null}},i=(t={})=>{let n=r(t);return new e(n,{client:`test`,cwd:n.path})},a=e=>({path:e,rootFiles:n.readdirSync(e),async findFilesByName(t){let r=[],i=e=>{let a=n.readdirSync(e,{withFileTypes:!0});for(let n of a)n.isDirectory()?n.name!==`node_modules`&&i(`${e}/${n.name}`):n.name===t&&r.push(`${e}/${n.name}`)};return i(e),r}});export{r as createMockInternalProject,i as createMockProject,a as createMockProjectFromPath};
|
package/dist/utils.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./semver-CxqsdmU_.cjs"),t=require("./path-pt0IDc1N.cjs");exports.getSemverLevel=e.t,exports.prettyPath=t.t;
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/lib/path.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Replaces user's home directory with `~` for display purposes.
|
|
4
|
+
*/
|
|
5
|
+
declare const prettyPath: (path: string) => string;
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/lib/semver.d.ts
|
|
8
|
+
type SemverLevel = 'major' | 'minor' | 'patch';
|
|
9
|
+
/**
|
|
10
|
+
* Get the semver update level between two versions using the semver package.
|
|
11
|
+
* Returns 'major', 'minor', 'patch', or null if versions match or can't be parsed.
|
|
12
|
+
*/
|
|
13
|
+
declare const getSemverLevel: (current: string, target: string) => SemverLevel | null;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { getSemverLevel, prettyPath };
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./semver-dZSpezIR.js";import{t}from"./path-DElA4WIM.js";export{e as getSemverLevel,t as prettyPath};
|
package/package.json
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@denvig/sdk",
|
|
3
|
+
"version": "0.7.0-alpha.4",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "Programmatic, in-process API for denvig — the logic layer behind the CLI",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"denvig-source": "./src/index.ts",
|
|
13
|
+
"import": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"require": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.cjs"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"./internal": {
|
|
23
|
+
"denvig-source": "./src/internal.ts",
|
|
24
|
+
"import": {
|
|
25
|
+
"types": "./dist/internal.d.ts",
|
|
26
|
+
"default": "./dist/internal.js"
|
|
27
|
+
},
|
|
28
|
+
"require": {
|
|
29
|
+
"types": "./dist/internal.d.ts",
|
|
30
|
+
"default": "./dist/internal.cjs"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"./utils": {
|
|
34
|
+
"denvig-source": "./src/utils.ts",
|
|
35
|
+
"import": {
|
|
36
|
+
"types": "./dist/utils.d.ts",
|
|
37
|
+
"default": "./dist/utils.js"
|
|
38
|
+
},
|
|
39
|
+
"require": {
|
|
40
|
+
"types": "./dist/utils.d.ts",
|
|
41
|
+
"default": "./dist/utils.cjs"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"./fs": {
|
|
45
|
+
"denvig-source": "./src/fs.ts",
|
|
46
|
+
"import": {
|
|
47
|
+
"types": "./dist/fs.d.ts",
|
|
48
|
+
"default": "./dist/fs.js"
|
|
49
|
+
},
|
|
50
|
+
"require": {
|
|
51
|
+
"types": "./dist/fs.d.ts",
|
|
52
|
+
"default": "./dist/fs.cjs"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"./testing": {
|
|
56
|
+
"denvig-source": "./src/test/mock.ts",
|
|
57
|
+
"import": {
|
|
58
|
+
"types": "./dist/testing.d.ts",
|
|
59
|
+
"default": "./dist/testing.js"
|
|
60
|
+
},
|
|
61
|
+
"require": {
|
|
62
|
+
"types": "./dist/testing.d.ts",
|
|
63
|
+
"default": "./dist/testing.cjs"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"publishConfig": {
|
|
68
|
+
"access": "public"
|
|
69
|
+
},
|
|
70
|
+
"files": [
|
|
71
|
+
"dist/",
|
|
72
|
+
"LICENSE",
|
|
73
|
+
"README.md"
|
|
74
|
+
],
|
|
75
|
+
"dependencies": {
|
|
76
|
+
"node-forge": "^1.4.0",
|
|
77
|
+
"semver": "^7.8.1",
|
|
78
|
+
"yaml": "^2.9.0",
|
|
79
|
+
"zod": "^4.4.3"
|
|
80
|
+
},
|
|
81
|
+
"devDependencies": {
|
|
82
|
+
"@types/node-forge": "^1.3.14",
|
|
83
|
+
"@types/semver": "^7.7.1",
|
|
84
|
+
"@denvig/tsconfig": "0.7.0-alpha.4"
|
|
85
|
+
},
|
|
86
|
+
"engines": {
|
|
87
|
+
"node": ">=22"
|
|
88
|
+
},
|
|
89
|
+
"repository": {
|
|
90
|
+
"type": "git",
|
|
91
|
+
"url": "git+https://github.com/marcqualie/denvig.git",
|
|
92
|
+
"directory": "packages/sdk"
|
|
93
|
+
},
|
|
94
|
+
"keywords": [
|
|
95
|
+
"cli",
|
|
96
|
+
"node",
|
|
97
|
+
"developer-tools",
|
|
98
|
+
"productivity",
|
|
99
|
+
"typescript",
|
|
100
|
+
"sdk"
|
|
101
|
+
],
|
|
102
|
+
"scripts": {
|
|
103
|
+
"build": "rm -rf dist && rolldown -c",
|
|
104
|
+
"check-types": "tsc --noEmit",
|
|
105
|
+
"codegen": "bin/codegen",
|
|
106
|
+
"test": "node --test --conditions=denvig-source --test-skip-pattern='node_modules' 'src/**/*.test.ts'",
|
|
107
|
+
"test:ci": "node --test --conditions=denvig-source --test-skip-pattern='node_modules' 'src/**/*.test.ts' --reporter=default"
|
|
108
|
+
}
|
|
109
|
+
}
|