zerostarter 0.1.38-canary.1 → 0.1.38

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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{A as e,C as t,D as n,E as r,F as i,I as a,M as o,N as s,O as c,P as l,S as u,T as d,_ as f,a as p,b as m,c as ee,d as h,f as g,g as _,h as v,i as y,j as b,k as x,l as S,m as C,n as te,o as ne,p as w,r as re,s as ie,t as ae,u as T,v as E,w as oe,x as D,y as O}from"../convert-DjNN2nhd.mjs";import{basename as se,delimiter as ce,dirname as le,join as k,parse as ue,resolve as A}from"node:path";import{existsSync as j,readFileSync as de,readdirSync as fe}from"node:fs";import{randomBytes as pe}from"node:crypto";import{createInterface as me}from"node:readline/promises";import{parseArgs as he}from"node:util";import{homedir as ge}from"node:os";var _e={name:`zerostarter`,version:`0.1.38-canary.1`,description:`Go from zero to a production-ready SaaS, rebranded and ready to ship.`,keywords:[`cli`,`saas`,`scaffold`,`starter`,`template`,`zerostarter`],homepage:`https://github.com/nrjdalal/zerostarter#readme`,bugs:`https://github.com/nrjdalal/zerostarter/issues`,license:`MIT`,author:{name:`Neeraj Dalal`,email:`admin@nrjdalal.com`,url:`https://nrjdalal.com`},repository:`nrjdalal/zerostarter`,funding:`https://github.com/sponsors/nrjdalal`,bin:{zerostarter:`dist/bin/index.mjs`},files:[`dist`],type:`module`,types:`./dist/index.d.mts`,exports:`./dist/index.mjs`,scripts:{build:`tsdown`,"check-types":`tsc --noEmit`,dev:`tsdown --watch`},devDependencies:{"@packages/config":`workspace:*`,"@types/bun":`catalog:`,"@types/node":`catalog:`,tsdown:`catalog:`,typescript:`catalog:`}};const M=()=>!!(process.stdin.isTTY&&process.stdout.isTTY),ve=(e,t=e)=>process.stdout.isTTY?`\x1b]8;;${e}\x07${t}\x1b]8;;\x07`:e,N=e=>ve(e,O(e)),P=e=>{process.stdout.write(`\n ${D(E.barStart)} ${e}\n ${D(E.bar)}\n`)},F=e=>{process.stdout.write(` ${D(E.bar)}\n ${D(E.barEnd)} ${e}\n`)},I=(e=`Cancelled`)=>{process.stdout.write(` ${D(E.barEnd)} ${d(e)}\n`)},L=e=>e.replace(/* @__PURE__ */ RegExp(`\x1B\\[[0-9;?]*[a-zA-Z]`,`g`),``).replace(/* @__PURE__ */ RegExp(`\x1B\\]8;;.*?\\x07`,`g`),``).length,R=(e,t=``,n=!1)=>{let r=`\n${e}\n`.split(`
2
+ import{A as e,C as t,D as n,E as r,F as i,I as a,M as o,N as s,O as c,P as l,S as u,T as d,_ as f,a as p,b as m,c as ee,d as h,f as g,g as _,h as v,i as y,j as b,k as x,l as S,m as C,n as te,o as ne,p as w,r as re,s as ie,t as ae,u as T,v as E,w as oe,x as D,y as O}from"../convert-D5950liy.mjs";import{basename as se,delimiter as ce,dirname as le,join as k,parse as ue,resolve as A}from"node:path";import{existsSync as j,readFileSync as de,readdirSync as fe}from"node:fs";import{randomBytes as pe}from"node:crypto";import{createInterface as me}from"node:readline/promises";import{parseArgs as he}from"node:util";import{homedir as ge}from"node:os";var _e={name:`zerostarter`,version:`0.1.38`,description:`Go from zero to a production-ready SaaS, rebranded and ready to ship.`,keywords:[`cli`,`saas`,`scaffold`,`starter`,`template`,`zerostarter`],homepage:`https://github.com/nrjdalal/zerostarter#readme`,bugs:`https://github.com/nrjdalal/zerostarter/issues`,license:`MIT`,author:{name:`Neeraj Dalal`,email:`admin@nrjdalal.com`,url:`https://nrjdalal.com`},repository:`nrjdalal/zerostarter`,funding:`https://github.com/sponsors/nrjdalal`,bin:{zerostarter:`dist/bin/index.mjs`},files:[`dist`],type:`module`,types:`./dist/index.d.mts`,exports:`./dist/index.mjs`,scripts:{build:`tsdown`,"check-types":`tsc --noEmit`,dev:`tsdown --watch`},devDependencies:{"@packages/config":`workspace:*`,"@types/bun":`catalog:`,"@types/node":`catalog:`,tsdown:`catalog:`,typescript:`catalog:`}};const M=()=>!!(process.stdin.isTTY&&process.stdout.isTTY),ve=(e,t=e)=>process.stdout.isTTY?`\x1b]8;;${e}\x07${t}\x1b]8;;\x07`:e,N=e=>ve(e,O(e)),P=e=>{process.stdout.write(`\n ${D(E.barStart)} ${e}\n ${D(E.bar)}\n`)},F=e=>{process.stdout.write(` ${D(E.bar)}\n ${D(E.barEnd)} ${e}\n`)},I=(e=`Cancelled`)=>{process.stdout.write(` ${D(E.barEnd)} ${d(e)}\n`)},L=e=>e.replace(/* @__PURE__ */ RegExp(`\x1B\\[[0-9;?]*[a-zA-Z]`,`g`),``).replace(/* @__PURE__ */ RegExp(`\x1B\\]8;;.*?\\x07`,`g`),``).length,R=(e,t=``,n=!1)=>{let r=`\n${e}\n`.split(`
3
3
  `),i=L(t),a=r.reduce((e,t)=>Math.max(e,L(t)),i),o=Math.max(a,54)+2,s=r.map(e=>` ${D(E.bar)} ${e}${` `.repeat(o-L(e))}${D(E.bar)}`).join(`
4
4
  `),c=n?E.cornerBL:E.connectL;process.stdout.write(` ${O(E.active)} ${t} ${D(E.barH.repeat(Math.max(o-i-1,1))+E.cornerTR)}\n${s}\n ${D(c+E.barH.repeat(o+2)+E.cornerBR)}\n`)},z=(e,t=[])=>{process.stdout.write(` ${O(E.active)} ${e}\n`);for(let e of t)process.stdout.write(` ${D(E.bar)} ${e}\n`)},ye=e=>{process.stdout.write(` ${u(E.active)} ${u(e)}\n`)},B=(e,t=[])=>{process.stdout.write(` ${r(E.warn)} ${r(e)}\n`);for(let e of t)process.stdout.write(` ${D(E.bar)} ${r(e)}\n`)},be=async(e,t,n)=>{let r=process.stdout,i=null;if(r.isTTY){let t=0;r.write(` ${oe(0,e)}`),i=setInterval(()=>{t+=1,r.write(`\r\x1b[K ${oe(t,e)}`)},400)}try{let e=await n();return i&&clearInterval(i),r.write(r.isTTY?`\r\x1b[K ${O(E.active)} ${t}\n`:` ${O(E.active)} ${t}\n`),e}catch(e){throw i&&clearInterval(i),r.isTTY&&r.write(`\r\x1B[K`),e}},xe=e=>{let t=e?`${u(E.radioOn)} Yes`:m(`${E.radioOff} Yes`),n=e?m(`${E.radioOff} No`):`${u(E.radioOn)} No`;return` ${D(E.bar)} ${t} ${m(`/`)} ${n}`},V=async(e,t=!0)=>{let n=process.stdout;return M()?new Promise(r=>{let i=t,a=process.stdin,o=Math.max(1,Math.ceil((5+L(e))/(n.columns||80)));n.write(` ${O(E.submit)} ${e}\n`),n.write(xe(i)),a.setRawMode(!0),a.resume(),a.setEncoding(`utf8`);let s=()=>{a.setRawMode(!1),a.pause(),a.removeListener(`data`,u)},c=()=>{n.write(`\r\x1b[K\x1b[${o}A\r\x1b[0J`)},l=()=>{s(),c(),r(i)};function u(t){t===``?(s(),c(),n.write(` ${O(E.submit)} ${m(e)}\n`),I(),process.exit(130)):t===`\r`||t===`
5
5
  `?l():t===`y`||t===`Y`?(i=!0,l()):t===`n`||t===`N`?(i=!1,l()):(t===`\x1B[C`||t===`\x1B[D`||t===`\x1B[A`||t===`\x1B[B`||t===`h`||t===`l`)&&(i=!i,n.write(`\r\x1b[K${xe(i)}`))}a.on(`data`,u)}):(n.write(` ${O(E.active)} ${e} ${m(t?`Yes`:`No`)}\n`),t)},Se=async(e,t)=>{if(t.length===0)return[];let n=process.stdout,r=new Set(t.filter(e=>e.checked).map(e=>e.value)),i=()=>t.filter(e=>r.has(e.value)).map(e=>e.label).join(`, `)||`none`;return M()?new Promise(a=>{let o=process.stdin,s=0,c=e=>{let n=t[e],i=r.has(n.value)?u(E.checkboxOn):m(E.checkboxOff),a=e===s?n.label:m(n.label);return` ${D(E.bar)} ${i} ${a}`},l=e=>{e||n.write(`\x1b[${t.length}A`);for(let e=0;e<t.length;e++)n.write(`\r\x1b[K${c(e)}\n`)};n.write(` ${O(E.submit)} ${e}\n`),l(!0),o.setRawMode(!0),o.resume(),o.setEncoding(`utf8`);let d=()=>{o.setRawMode(!1),o.pause(),o.removeListener(`data`,f)};function f(o){if(o===``)d(),n.write(`\x1b[${t.length+1}A\r\x1b[0J ${O(E.submit)} ${m(e)}\n`),I(),process.exit(130);else if(o===`\r`||o===`
@@ -7,7 +7,7 @@ import{A as e,C as t,D as n,E as r,F as i,I as a,M as o,N as s,O as c,P as l,S a
7
7
  `).find(e=>e.startsWith(n));return r?r.slice(n.length).trim():``},U=(e,t,n)=>{let r=`${t}=`,i=b(e).split(`
8
8
  `),a=i.findIndex(e=>e.startsWith(r));if(a>=0)i[a]=`${r}${n}`;else{for(;i.length&&i[i.length-1]===``;)i.pop();i.push(`${r}${n}`,``)}l(e,i.join(`
9
9
  `))},De=e=>{let t=Ee(e);H(t,`BETTER_AUTH_SECRET`)||U(t,`BETTER_AUTH_SECRET`,pe(32).toString(`base64`)),H(t,`AGENT_SIGNIN_ENABLED`)||U(t,`AGENT_SIGNIN_ENABLED`,`true`)},W=e=>{let t=k(e,`.env`);return x(t)&&H(t,`POSTGRES_URL`)!==``},Oe=e=>{let t=e.match(/postgres(?:ql)?:\/\/[\w.:@\-/%?=&]+/);if(!t)return null;let n=e.match(/name "([^" ]+) :\d+" started/),r=e.match(/similar name "([^"]+)"/);return{url:t[0],container:n?n[1]:r?r[1]:``}},ke=async(e,t)=>{let n=t?[`--bun`,we,`-k`,`-c`]:[`--bun`,we,`-k`],r;try{r=await v(`bunx`,n,e)}catch(e){let t=e;r=[t.stdout,t.stderr].filter(Boolean).join(`
10
- `)}return{launch:Oe(r),out:r}},Ae=e=>new Promise(t=>setTimeout(t,e)),je=async e=>{if(e)for(let t=0;t<30;t++){if(await w(`docker`,[`exec`,e,`pg_isready`,`-U`,`postgres`]))return;await Ae(1e3)}},Me=async e=>{let t=Ee(e),n=await ke(e,!1),r=n.launch?n:await ke(e,!0);if(!r.launch)throw Error(r.out.trim()||`pglaunch did not print a connection URL`);U(t,`POSTGRES_URL`,r.launch.url),await je(r.launch.container),await f(`bun`,[`run`,`db:migrate`],{cwd:e,label:`Provisioning a local Postgres database`,done:`Provisioned a local Postgres database`})},G=`gitpick@6.0.0`,K=async e=>{await f(`bun`,[`install`],{cwd:e,label:`Installing dependencies`,done:`Installed dependencies`})},Ne=async()=>{if(!await w(`bun`,[`--version`]))throw Error(`bun is not on PATH`)},Pe=async(e=Ne,t=!!process.versions.bun,n=process.env.npm_config_user_agent||``)=>{if(t||n.startsWith(`bun/`))return!0;try{return await e(),!0}catch{return!1}},Fe=async(e,t=`main`)=>{await v(`bunx`,[`--bun`,G,`https://github.com/nrjdalal/zerostarter/tree/${t}`,e])},Ie=async(e,t=`main`)=>{await v(`bunx`,[`--bun`,G,`https://github.com/nrjdalal/zerostarter/tree/${t}`,e,`-o`])},Le=async(e=`main`)=>{let t=`https://raw.githubusercontent.com/nrjdalal/zerostarter/${e}/.gitpickignore`,n=await fetch(t);if(!n.ok)throw Error(`Could not fetch .gitpickignore from ${e} (HTTP ${n.status}).`);return n.text()},Re=async e=>(await v(`git`,[`status`,`--porcelain`],e)).trim()===``,ze=async(e,t)=>{for(let n of t)try{await v(`git`,[`checkout`,`--`,n],e),await v(`git`,[`clean`,`-fd`,`--`,n],e)}catch{}},Be=async e=>{await v(`git`,[`reset`,`--hard`,`HEAD`],e),await v(`git`,[`clean`,`-fd`],e)},Ve=async(e,t,n)=>{if(!x(k(e,`.git`)))throw Error(t);if(!await Re(e))throw Error(n)},He=async(e,t,n)=>{try{await n()}catch(n){throw await Be(e),console.log(t),n}},Ue=async e=>{await v(`git`,[`init`,`-q`,`-b`,`canary`],e)},We=async(e,t)=>{await v(`git`,[`branch`,t],e)},q=async(e,t)=>{await v(`git`,[`add`,`-A`],e);try{await v(`git`,[`commit`,`--no-verify`,`-q`,`-m`,t],e)}catch{}},J=(e,t)=>{try{return he(t)}catch(t){process.stderr.write(`${d(t instanceof Error?t.message:String(t))}\n\n`),process.stdout.write(`${e}\n`),process.exit(1)}},Ge=(e=process.env.npm_config_user_agent||``)=>e.startsWith(`bun/`)?`bunx`:e.startsWith(`pnpm/`)?`pnpm dlx`:e.startsWith(`yarn/`)?`yarn dlx`:e.startsWith(`npm/`)?`npx`:`unknown`,Ke=(e=process.platform)=>e===`win32`?{cmd:`powershell`,args:[`-Command`,`irm bun.sh/install.ps1 | iex`]}:{cmd:`bash`,args:[`-c`,`curl -fsSL https://bun.sh/install | bash`]},qe=(e=process.argv.slice(2))=>[`zerostarter`,...e].join(` `),Je=()=>k(process.env.BUN_INSTALL||k(ge(),`.bun`),`bin`),Y=async(e=!1)=>{if(await Pe())return;let n=Ge(),r=`bunx --bun ${qe()}`;if(console.error(d(`Seems like you are using ${n===`unknown`?`npx/pnpx`:n} or Windows, try using:`)),console.error(t(` ${r}`)),console.error(``),e||M()&&await V(`Or install bun now and continue?`,!0)){let{cmd:e,args:n}=Ke();console.error(`Installing bun from https://bun.sh/install ...`);try{if(await _(e,n),process.env.PATH=`${Je()}${ce}${process.env.PATH||``}`,await Pe())return;console.error(d(`
10
+ `)}return{launch:Oe(r),out:r}},Ae=e=>new Promise(t=>setTimeout(t,e)),je=async e=>{if(e)for(let t=0;t<30;t++){if(await w(`docker`,[`exec`,e,`pg_isready`,`-U`,`postgres`]))return;await Ae(1e3)}},Me=async e=>{let t=Ee(e),n=await ke(e,!1),r=n.launch?n:await ke(e,!0);if(!r.launch)throw Error(r.out.trim()||`pglaunch did not print a connection URL`);U(t,`POSTGRES_URL`,r.launch.url),await je(r.launch.container),await f(`bun`,[`run`,`db:migrate`],{cwd:e,label:`Provisioning a local Postgres database`,done:`Provisioned a local Postgres database`})},G=`gitpick@6.1.1`,K=async e=>{await f(`bun`,[`install`],{cwd:e,label:`Installing dependencies`,done:`Installed dependencies`})},Ne=async()=>{if(!await w(`bun`,[`--version`]))throw Error(`bun is not on PATH`)},Pe=async(e=Ne,t=!!process.versions.bun,n=process.env.npm_config_user_agent||``)=>{if(t||n.startsWith(`bun/`))return!0;try{return await e(),!0}catch{return!1}},Fe=async(e,t=`main`)=>{await v(`bunx`,[`--bun`,G,`https://github.com/nrjdalal/zerostarter/tree/${t}`,e])},Ie=async(e,t=`main`)=>{await v(`bunx`,[`--bun`,G,`https://github.com/nrjdalal/zerostarter/tree/${t}`,e,`-o`])},Le=async(e=`main`)=>{let t=`https://raw.githubusercontent.com/nrjdalal/zerostarter/${e}/.gitpickignore`,n=await fetch(t);if(!n.ok)throw Error(`Could not fetch .gitpickignore from ${e} (HTTP ${n.status}).`);return n.text()},Re=async e=>(await v(`git`,[`status`,`--porcelain`],e)).trim()===``,ze=async(e,t)=>{for(let n of t)try{await v(`git`,[`checkout`,`--`,n],e),await v(`git`,[`clean`,`-fd`,`--`,n],e)}catch{}},Be=async e=>{await v(`git`,[`reset`,`--hard`,`HEAD`],e),await v(`git`,[`clean`,`-fd`],e)},Ve=async(e,t,n)=>{if(!x(k(e,`.git`)))throw Error(t);if(!await Re(e))throw Error(n)},He=async(e,t,n)=>{try{await n()}catch(n){throw await Be(e),console.log(t),n}},Ue=async e=>{await v(`git`,[`init`,`-q`,`-b`,`canary`],e)},We=async(e,t)=>{await v(`git`,[`branch`,t],e)},q=async(e,t)=>{await v(`git`,[`add`,`-A`],e);try{await v(`git`,[`commit`,`--no-verify`,`-q`,`-m`,t],e)}catch{}},J=(e,t)=>{try{return he(t)}catch(t){process.stderr.write(`${d(t instanceof Error?t.message:String(t))}\n\n`),process.stdout.write(`${e}\n`),process.exit(1)}},Ge=(e=process.env.npm_config_user_agent||``)=>e.startsWith(`bun/`)?`bunx`:e.startsWith(`pnpm/`)?`pnpm dlx`:e.startsWith(`yarn/`)?`yarn dlx`:e.startsWith(`npm/`)?`npx`:`unknown`,Ke=(e=process.platform)=>e===`win32`?{cmd:`powershell`,args:[`-Command`,`irm bun.sh/install.ps1 | iex`]}:{cmd:`bash`,args:[`-c`,`curl -fsSL https://bun.sh/install | bash`]},qe=(e=process.argv.slice(2))=>[`zerostarter`,...e].join(` `),Je=()=>k(process.env.BUN_INSTALL||k(ge(),`.bun`),`bin`),Y=async(e=!1)=>{if(await Pe())return;let n=Ge(),r=`bunx --bun ${qe()}`;if(console.error(d(`Seems like you are using ${n===`unknown`?`npx/pnpx`:n} or Windows, try using:`)),console.error(t(` ${r}`)),console.error(``),e||M()&&await V(`Or install bun now and continue?`,!0)){let{cmd:e,args:n}=Ke();console.error(`Installing bun from https://bun.sh/install ...`);try{if(await _(e,n),process.env.PATH=`${Je()}${ce}${process.env.PATH||``}`,await Pe())return;console.error(d(`
11
11
  bun is installed but isn't on this shell's PATH yet. Open a new terminal and re-run:`)),console.error(t(` ${r}`))}catch{console.error(d(`
12
12
  Could not install bun. Install it from https://bun.sh, then re-run:`)),console.error(t(` ${r}`))}}process.exit(1)},X=[{value:`allowlist`,flag:`allowlist`,help:`Console access by email domain or address`,label:`Allowlist (grant console access by domain)`},{value:`apiDocs`,flag:`api-docs`,help:`The /api/docs API reference`,label:`API docs`},{value:`blog`,flag:`blog`,help:`The /blog`,label:`Blog`},{value:`docs`,flag:`docs`,help:`The /docs`,label:`Docs`},{value:`internalDocs`,flag:`internal-docs`,help:`The /console/docs internal docs`,label:`Internal (console) docs`},{value:`waitlist`,flag:`waitlist`,help:`The /waitlist (off leaves a plain landing home)`,label:`Waitlist (else a plain landing home)`}],Ye=X.filter(e=>!g[e.value]).map(e=>e.flag),Xe=X.map(e=>` ${`--${e.flag},`.padEnd(18)}${`--no-${e.flag}`.padEnd(21)}${e.help}`).join(`
13
13
  `),Ze=Object.fromEntries(X.flatMap(e=>[[e.flag,{type:`boolean`}],[`no-${e.flag}`,{type:`boolean`}]])),Qe=`Usage:
@@ -40,8 +40,8 @@ branch; push when ready.
40
40
 
41
41
  Options:
42
42
  -y, --yes Skip the confirmation prompt
43
- -h, --help Display help`,rt=e=>[...e?[]:[`set POSTGRES_URL in .env`],t(`bun run db:migrate`),t(`bun run dev`),t(`git push`)],it=async e=>{let{positionals:t,values:n}=J(nt,{allowPositionals:!0,args:e,options:{help:{short:`h`,type:`boolean`},yes:{short:`y`,type:`boolean`}}});if(n.help){console.log(nt);return}await Y(!!n.yes);let i=A(t[0]??`.`),a=se(i),o=M()&&!n.yes;if(await Ve(i,`No git repository in ${i}. reinit re-scaffolds an existing repo; use init for a new project.`,`Working tree has uncommitted changes. Commit or stash them first; reinit deletes every tracked file.`),P(N(`https://zerostarter.dev`)),o&&!await V(`Delete every file in ${a} (keeping .git and .env*) and re-scaffold?`,!1)){I(`Aborted`);return}await He(i,r(`reinit failed; restored your committed files (deleted gitignored files, except .env*, are gone).`),async()=>{c(i),await Ie(i),z(`Fetched the latest ZeroStarter (kept .git and .env*)`),ae(i,{name:a}),z(`Rebranded to ${a}`),await K(i),await T(i),De(i),await q(i,`ci(reinit): re-baseline as ${a}`)}),R(rt(W(i)).join(`
44
- `),`Next steps`),F(u(`${a} re-scaffolded; .git history, remote, and .env* files are intact`))},at=`Usage:
43
+ -h, --help Display help`,rt=e=>[...e?[]:[`set POSTGRES_URL in .env`],t(`bun run db:migrate`),t(`bun run dev`),t(`git push`)],it=async e=>{let{positionals:t,values:n}=J(nt,{allowPositionals:!0,args:e,options:{help:{short:`h`,type:`boolean`},yes:{short:`y`,type:`boolean`}}});if(n.help){console.log(nt);return}await Y(!!n.yes);let i=A(t[0]??`.`),a=se(i),o=M()&&!n.yes;await Ve(i,`No git repository in ${i}. reinit re-scaffolds an existing repo; use init for a new project.`,`Working tree has uncommitted changes. Commit or stash them first; reinit deletes every tracked file.`),P(N(`https://zerostarter.dev`)),o&&!await V(`Delete every file in ${a} (keeping .git and .env*) and re-scaffold?`,!1)?I(`Aborted`):(await He(i,r(`reinit failed; restored your committed files (deleted gitignored files, except .env*, are gone).`),async()=>{c(i),await Ie(i),z(`Fetched the latest ZeroStarter (kept .git and .env*)`),ae(i,{name:a}),z(`Rebranded to ${a}`),await K(i),await T(i),De(i),await q(i,`ci(reinit): re-baseline as ${a}`)}),R(rt(W(i)).join(`
44
+ `),`Next steps`),F(u(`${a} re-scaffolded; .git history, remote, and .env* files are intact`)))},at=`Usage:
45
45
  $ bunx zerostarter sync [dir] [options]
46
46
 
47
47
  Re-baseline an existing fork (default .) on the latest ZeroStarter: a gitpick overlay
@@ -0,0 +1,161 @@
1
+ import{delimiter as e,dirname as t,isAbsolute as n,join as r,relative as i,resolve as a,sep as o}from"node:path";import{existsSync as s,mkdirSync as c,readFileSync as l,readdirSync as u,rmSync as d,writeFileSync as f}from"node:fs";import{createHash as p}from"node:crypto";import{spawn as m}from"node:child_process";import{access as h}from"node:fs/promises";const g=e=>{let t=[],n=[],r=!1;for(let i of e.split(`
2
+ `)){let e=i.trim();e&&(!r&&e.startsWith(`# PRESERVE_ON_SYNC`)?(n=e.slice(18).replace(/^\s*-\s*/,``).split(`,`).map(e=>e.trim()).filter(Boolean),r=!0):e.startsWith(`#`)||t.push(e))}return{excludes:t,preserve:n}},_=e=>s(e),v=e=>l(e,`utf8`),y=(e,n)=>{c(t(e),{recursive:!0}),f(e,n)},b=e=>{d(e,{force:!0,recursive:!0})},x=/* @__PURE__ */ new Set([`node_modules`,`.next`,`.turbo`,`dist`]),S=(e,t=!0)=>{for(let n of u(e,{withFileTypes:!0})){let i=r(e,n.name);if(n.name===`.git`){if(t)continue;d(i,{force:!0,recursive:!0})}else n.isDirectory()?x.has(n.name)?d(i,{force:!0,recursive:!0}):(S(i,!1),u(i).length===0&&d(i,{force:!0,recursive:!0})):n.name.startsWith(`.env`)||d(i,{force:!0})}},C=e=>{let t=[];for(let n of u(e,{withFileTypes:!0})){if(n.name===`.git`||x.has(n.name))continue;let i=r(e,n.name);n.isDirectory()?t.push(...C(i)):n.name===`package.json`&&t.push(i)}return t},w=e=>JSON.parse(v(e)),T=(e,t)=>{y(e,`${JSON.stringify(t,null,2)}\n`)},ee=(e,t)=>{if(!s(e))return!1;let n=v(e),r=n.replace(t,``);return r!==n&&(f(e,r),!0)},E=[`homepage`,`bugs`,`license`,`author`,`repository`,`funding`],te=[`name`,`version`,...E],ne=(e,t)=>{let n={...e,...t};return Object.keys(n).length>0?n:void 0},re=(e,t)=>{let n=Array.isArray(e)?e:[],r=Array.isArray(t)?t:[];return n.length||r.length?[.../* @__PURE__ */ new Set([...r,...n])]:void 0},ie=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`,`resolutions`,`catalog`,`scripts`,`overrides`],ae=(e,t,n)=>{let r={...t};for(let n of Object.keys(e))n in t||(r[n]=e[n]);for(let n of ie){let i=ne(e[n],t[n]);i&&(r[n]=i)}let i=re(e.workspaces,t.workspaces);if(i&&(r.workspaces=i),n)for(let t of te)t in e?r[t]=e[t]:delete r[t];return r},D=(e,t,n=process.stdout)=>r=>n.isTTY?`\x1b[${e}m${r}\x1b[${t}m`:r,O=D(`36`,`39`),oe=D(`32`,`39`),se=D(`33`,`39`),k=D(`90`,`39`),A=D(`2`,`22`),ce=D(`31`,`39`,process.stderr),le=D(`2`,`22`,process.stderr),ue=D(`38;5;208`,`39`),j=[`◇`,`◆`],M=(e,t)=>{let n=(e%j.length+j.length)%j.length;return`${O(j[n])} ${t}`},N={barStart:`┌`,bar:`│`,barEnd:`└`,active:`◆`,submit:`◇`,radioOn:`●`,radioOff:`○`,checkboxOn:`◼`,checkboxOff:`◻`,warn:`▲`,error:`■`,barH:`─`,cornerTR:`╮`,connectL:`├`,cornerBL:`╰`,cornerBR:`╯`};var P=class extends Error{constructor(...e){super(...e),this.name=`SubprocessError`,this.stdout=``,this.stderr=``}};const F=[`.exe`,`.com`],I=e=>e.replaceAll(/([()\][%!^"`<>&|;, *?])/g,`^$1`),de=e=>I(I(`"${e.replaceAll(/(\\*)"/g,`$1$1\\"`).replace(/(\\*)$/,`$1$1`)}"`)),fe=async(t,n,r)=>{if(F.some(e=>t.toLowerCase().endsWith(e)))return!0;let i=(r.PATH||r.Path||``).split(e).filter(Boolean).map(e=>e.replace(/^"(.*)"$/,`$1`));try{return await Promise.any([n,...i].flatMap(e=>F.map(n=>h(`${a(e,t)}${n}`)))),!0}catch{return!1}},pe=async(e,t,n,r=process.platform===`win32`)=>{let i=n.cwd?String(n.cwd):`.`,a=n.env||process.env;return r&&!n.shell&&!await fe(e,i,a)?[I(e),t.map(de),{...n,shell:!0}]:[e,t,n]},L=async(e,t,n,r)=>{let i=[e,...t].join(` `),[a,o,s]=await pe(e,t,n);s.shell&&o.length>0&&(a=[a,...o].join(` `),o=[]);let c=m(a,o,s),l=``,u=``;return new Promise((e,t)=>{let n=(e,n,r)=>{let i=new P(e,r?{cause:r}:void 0);i.stdout=l,i.stderr=u,i.exitCode=n,t(i)},a=e=>{e.code!==`ERR_STREAM_PREMATURE_CLOSE`&&e.code!==`EPIPE`&&n(`Command failed: ${i}`,void 0,e)};c.stdout&&(c.stdout.setEncoding(`utf8`),c.stdout.on(`data`,e=>{l+=e,r?.(e)}),c.stdout.on(`error`,a)),c.stderr&&(c.stderr.setEncoding(`utf8`),c.stderr.on(`data`,e=>{u+=e,r?.(e)}),c.stderr.on(`error`,a)),c.on(`error`,e=>n(`Command failed: ${i}`,void 0,e)),c.on(`close`,(t,r)=>{if(r)return n(`Command was terminated with ${r}: ${i}`);if(t!==0)return n(`Command failed with exit code ${t}: ${i}`,t??void 0);e({stdout:l,stderr:u})})})},R=async(e,t,n)=>{let{stdout:r}=await L(e,t,{cwd:n,stdio:[`ignore`,`pipe`,`pipe`]});return r},z=async(e,t,n)=>{await L(e,t,{cwd:n,stdio:`inherit`})},me=async(e,t)=>{try{return await L(e,t,{stdio:`ignore`}),!0}catch{return!1}},he=/* @__PURE__ */ RegExp(`\x1B\\[[0-9;?]*[a-zA-Z]`,`g`),B=e=>e.replace(he,``),V=/* @__PURE__ */ new WeakSet,ge=e=>{if(process.stderr.write(`\n ${ce(e instanceof Error?e.message:String(e))}\n`),!(e instanceof P)||V.has(e))return;let t=(e.stderr||e.stdout||``).trim();if(!t)return;let n=B(t).split(`
3
+ `).map(e=>e.trimEnd()).filter(Boolean).slice(-12);for(let e of n)process.stderr.write(` ${le(e)}\n`)},_e=async(e,t,n)=>{let r=process.stdout,i=n.label??``;if(!r.isTTY){i&&r.write(` ${O(N.active)} ${i}\n`),await z(e,t,n.cwd);return}let a=n.lines??3,o=[],s=0,c=0,l=``,u=``,d=()=>(r.columns||80)-1,f=e=>{r.write(e?`\x1B[?7h`:`\x1B[?7l`)},p=()=>{c>0&&(r.write(`[${c}A`),c=0)},m=()=>{p();let e=0;r.write(` ${M(s,i)}\n`),e++;for(let t of o.slice(-a))r.write(` ${k(N.bar)} ${A(t.slice(0,Math.max(0,d()-5)))}\n`),e++;c=e},h=e=>{u+=e,l+=e;let t=l.split(`
4
+ `);l=t.pop()??``;for(let e of t)o.push(B(e).replace(/\r/g,``).replace(/\t/g,` `).trimEnd()),m()};m(),f(!1);let g=()=>{f(!0),process.exit(130)};process.once(`SIGINT`,g);let _=setInterval(()=>{s+=1,m()},400),v=()=>{clearInterval(_),process.removeListener(`SIGINT`,g)};try{await L(e,t,{cwd:n.cwd,stdio:[`ignore`,`pipe`,`pipe`]},h)}catch(e){throw v(),p(),f(!0),r.write(u),e&&typeof e==`object`&&V.add(e),e}v(),p(),f(!0),r.write(` ${O(N.active)} ${n.done??i}\n`);for(let e of o.slice(-a))r.write(` ${k(N.bar)} ${A(e.slice(0,Math.max(0,d()-5)))}\n`)},H={allowlist:!1,apiDocs:!0,blog:!0,docs:!0,internalDocs:!0,waitlist:!1},ve=e=>`// Optional surfaces a fork enables or disables. Typed boolean (not \`as const\`) so a fork can flip them and the runtime gates are not dead code. Off means the routes 404 and the links, nav, sitemap, llms, and search drop the surface. waitlist off makes the home a plain landing page.
5
+ export const features = {
6
+ allowlist: ${e.allowlist},
7
+ apiDocs: ${e.apiDocs},
8
+ blog: ${e.blog},
9
+ docs: ${e.docs},
10
+ internalDocs: ${e.internalDocs},
11
+ waitlist: ${e.waitlist},
12
+ }
13
+
14
+ export type Feature = keyof typeof features`,ye=({name:e},t=H)=>{let n=e.charAt(0).toUpperCase()+e.slice(1);return`// Brand identity for this app: the single source a fork edits to rebrand. web reads it via lib/config.ts.
15
+ export const site = {
16
+ name: ${JSON.stringify(n)},
17
+ description: ${JSON.stringify(`${n} is just getting started. Tell its story here.`)},
18
+ tagline: "Your tagline, ready when you are.",
19
+ social: {
20
+ discord: "",
21
+ github: "",
22
+ x: "",
23
+ },
24
+ // Local-only dev agent identity (api/hono agents router).
25
+ agent: {
26
+ name: "LocalAgent",
27
+ email: "agent@local.host",
28
+ },
29
+ // Injectable long-form text blocks. A product sets its own, or leaves them empty.
30
+ apiReferenceDescription: "",
31
+ llmsFullPreamble: "",
32
+ } as const
33
+
34
+ export type Site = typeof site
35
+
36
+ ${ve(t)}
37
+ `},be=()=>`import { features, site } from "@packages/config/site"
38
+ import { redirect } from "next/navigation"
39
+
40
+ // Fresh fork: the waitlist capture when the waitlist feature is on, otherwise a plain landing page. Replace this with your real home when ready.
41
+ export default function Home() {
42
+ if (features.waitlist) redirect("/waitlist")
43
+
44
+ return (
45
+ <main className="flex min-h-svh flex-col items-center justify-center p-8 text-center">
46
+ <div className="mx-auto flex w-full max-w-xl flex-col items-center">
47
+ <h1 className="mb-4 text-5xl font-bold tracking-tight sm:text-6xl">{site.name}</h1>
48
+ <p className="text-muted-foreground max-w-md text-lg">{site.tagline}</p>
49
+ </div>
50
+ </main>
51
+ )
52
+ }
53
+ `,U=()=>`# AGENTS.md
54
+
55
+ Guidance for AI coding agents working in this repository.
56
+
57
+ ## Instructions
58
+
59
+ - ALWAYS: Use \`@/\` for imports, and follow the \`design\` skill for UI and styling conventions.
60
+ - ALWAYS: Keep documentation in sync with every change.
61
+ - NEVER: Include "Co-authored-by" in commit messages.
62
+ - NEVER: Use em-dashes (the long dash, U+2014) in code, comments, docs, or copy. Regular hyphens are fine; for a pause or aside, use a comma, colon, or period.
63
+
64
+ ## Skills
65
+
66
+ Skills live in \`.agents/skills\` (symlinked to \`.claude/skills\` and \`.github/skills\`, so every agent tool reads the same files). Each is a \`SKILL.md\` with a \`description\` trigger and a literal procedure. Start with \`codebase-map\` to orient, then load the task skill that fits.
67
+
68
+ These tables are generated from each skill's own description by \`bun .github/scripts/skills-manager.ts\`, which a pre-commit hook runs for you. **Custom** skills are maintained here; **vendored** skills are copied verbatim from an upstream project (re-vendor to update, do not hand-edit).
69
+
70
+ **Custom**
71
+
72
+ <!-- skills:custom -->
73
+
74
+ <!-- /skills:custom -->
75
+
76
+ **Vendored** (upstream, copied verbatim)
77
+
78
+ <!-- skills:vendored -->
79
+
80
+ <!-- /skills:vendored -->
81
+ `,xe=({name:e})=>`# ${e.charAt(0).toUpperCase()+e.slice(1)}
82
+
83
+ Built on top of [ZeroStarter](https://zerostarter.dev).
84
+
85
+ ## Development
86
+
87
+ \`\`\`bash
88
+ bun run dev
89
+ \`\`\`
90
+
91
+ This serves named \`.localhost\` dev URLs via portless (\`bunx portless list\` shows them); \`PORTLESS=0 bun run dev\` uses fixed ports instead (web \`:3000\`, api \`:4000\`).
92
+ `,Se=()=>`---
93
+ slug: /docs
94
+ title: Introduction
95
+ description: Documentation.
96
+ ---
97
+
98
+ # Introduction
99
+
100
+ This is your documentation home. Start writing, this page is yours.
101
+ `,Ce=()=>`---
102
+ slug: /console/docs
103
+ title: Introduction
104
+ description: Internal documentation.
105
+ ---
106
+
107
+ # Introduction
108
+
109
+ Your team's internal docs live here.
110
+ `,we=e=>`---
111
+ title: Blog
112
+ description: Latest articles and updates
113
+ createdAt: ${e}
114
+ ---
115
+
116
+ ## Recent Posts
117
+
118
+ <BlogPostList />
119
+ `,Te=e=>`---
120
+ title: Hello World
121
+ description: The first post on your new blog.
122
+ createdAt: ${e}
123
+ publishedAt: ${e}
124
+ ---
125
+
126
+ ## Hello World
127
+
128
+ Your very first post. Replace it with something worth reading.
129
+ `,Ee=()=>`import type { DocsConfig } from "./src/lib/docs"
130
+
131
+ const docsConfig = {
132
+ docs: {
133
+ "Getting Started": [
134
+ {
135
+ "/docs": {
136
+ title: "Introduction",
137
+ description: "Documentation.",
138
+ },
139
+ },
140
+ ],
141
+ },
142
+ console: {
143
+ "Getting Started": [
144
+ {
145
+ "/console/docs": {
146
+ title: "Introduction",
147
+ description: "Internal documentation.",
148
+ },
149
+ },
150
+ ],
151
+ },
152
+ } satisfies DocsConfig
153
+
154
+ export default docsConfig
155
+ `,W=`https://github.com/nrjdalal/zerostarter`,G=`.agents/skills/.sync.json`,K=`main`,q=`AGENTS.md`,J=()=>({adopted:[],customized:[],forkOwned:[],unverified:[]}),Y=e=>p(`sha256`).update(e.replace(/\r\n/g,`
156
+ `)).digest(`hex`).slice(0,12),X=e=>e.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``)||`app`,Z=(e,t,n)=>e.replaceAll(`ZeroStarter`,()=>n).replace(/(?<!bunx )zerostarter(?! scaffolding CLI)/g,t),De=`> Synced from ${W}.`,Oe=()=>`> [!CAUTION]\n${De} Customize this skill or remove this note to stop syncing.`,ke=e=>e.replace(/^https?:\/\/github\.com\//,``).replace(/\/+$/,``),Ae=ke(W),je=e=>{let t=e.split(`
157
+ `);if(t[0]===void 0||t[0].trim()!==`---`)return``;for(let e of t.slice(1)){if(e.trim()===`---`)break;if(e.startsWith(`source:`))return e.slice(7).trim()}return``},Me=e=>u(e,{withFileTypes:!0}).filter(t=>t.isDirectory()&&_(r(e,t.name,`SKILL.md`))).map(e=>e.name).sort(),Ne=e=>{let t=r(e,G);if(!_(t))return{};try{return w(t)}catch{return{}}},Pe=e=>{let t=r(e,`.agents/skills`),n=/* @__PURE__ */ new Map;if(!_(t))return n;for(let e of Me(t))n.set(e,v(r(t,e,`SKILL.md`)));return n},Fe=(e,t,n,r,i=!1)=>{let a=e.replace(/\r\n/g,`
158
+ `).split(`
159
+ `),o=a.indexOf(`---`),s=a.indexOf(`---`,o+1);if(o!==0||s===-1)throw Error(`.agents/skills/${r}/SKILL.md has no frontmatter to reconcile (the skill shape drifted). Update packages/cli/src/skills.ts.`);let c=je(e),l=i||c===``||c===`local`?W:c,u=a.slice(o+1,s).map(e=>e.startsWith(`source:`)?`source: ${l}`:Z(e,t,n));u.some(e=>e.startsWith(`source:`))||u.push(`source: ${l}`);let d=Z(a.slice(s+1).join(`
160
+ `),t,n).replace(/^\n+/,``),f=l===W?`${Oe()}\n\n`:``;return`---\n${u.join(`
161
+ `)}\n---\n\n${f}${d}`},Ie=(e,t,n)=>{let i=r(e,`.agents/skills`),a=J();if(!_(i))return a;let o=X(t.name),s=Ne(e),c={};for(let e of Me(i)){let l=r(i,e,`SKILL.md`),u=v(l),d=Fe(u,o,t.name,e),f=n===void 0?void 0:n.get(e),p=s[e];if(f!==void 0){let n=je(f),r=t=>{y(l,f),t.push(e),p&&(c[e]=p)},i=ke(n);if(n!==``&&i!==Ae||i===Ae&&!f.includes(De)){r(a.forkOwned);continue}if(p){if(p.written!==Y(f)){r(a.customized);continue}}else Y(f)!==Y(d)&&Y(f)!==Y(Fe(u,o,t.name,e,!0))&&a.unverified.push(e)}y(l,d),c[e]={ref:K,upstream:Y(u),written:Y(d)},a.adopted.push(e)}return s[`AGENTS.md`]&&(c[q]=s[q]),T(r(e,G),c),a},Q=e=>e.replace(/(<!-- skills:(custom|vendored) -->)[\s\S]*?(<!-- \/skills:\2 -->)/g,`$1$3`),Le=(e,t,n)=>{let i=r(e,q),a=r(e,G),o=Ne(e),s=X(t.name),c=(e,t)=>(y(i,t),o[q]={ref:K,upstream:Y(e),written:Y(Q(t))},T(a,o),`adopted`);if(n===void 0){if(!_(i))return c(U(),U());let e=v(i);return c(e,Z(e,s,t.name))}let{before:l,upstream:u}=n;if(u===void 0||u===l)return`absent`;if(l!==void 0){let e=o[q];if(!(e?e.written===Y(Q(l)):Y(Q(l))===Y(Q(U()))))return y(i,l),e?`customized`:`forkOwned`}return c(u,Z(u,s,t.name))},Re=e=>{let t=r(e,`AGENTS.md`);if(!_(t))return!1;let n=v(t);return!n.includes(`<!-- skills:custom -->`)||!n.includes(`<!-- skills:vendored -->`)},ze=async e=>{if(_(r(e,`.github/scripts/skills-manager.ts`)))try{await R(`bun`,[`.github/scripts/skills-manager.ts`],e)}catch{}},Be=(e,t)=>{let n=w(r(e,`package.json`)).name;return n?Ie(e,{name:n},t):J()},Ve=(e,t)=>{let n=w(r(e,`package.json`)).name;return n?Le(e,{name:n},t):`absent`},He=e=>{let t=r(e,q);return _(t)?v(t):void 0},$=(e,...t)=>r(e,...t),Ue=e=>{let t=$(e,`.gitpickignore`);if(!_(t))return;let s=a(e),c=(e,t)=>{throw Error(`.gitpickignore entry "${e}" ${t}; the in-place converter only removes literal paths under the root.`)},l=g(v(t)).excludes.map(e=>{/[*?![\]]/.test(e)&&c(e,`is not a literal path (a glob or negation would diverge from gitpick's fetch)`);let t=i(s,a(s,e));return(n(e)||!t||t===`..`||t.startsWith(`..${o}`)||n(t))&&c(e,`is not inside the project`),r(s,t)});for(let e of l)b(e);b(t)},We=/[ \t]*\{[^}\r\n]*href:[ \t]*["']\/hire["'][^}\r\n]*\},?[ \t]*\r?\n/,Ge=(e,t)=>{let n=/* @__PURE__ */ new Date,r=n.toISOString().slice(0,10),i=[n.getFullYear(),n.getMonth()+1,n.getDate()].map(e=>String(e).padStart(2,`0`)).join(`-`),a=i<r?i:r;y($(e,`web/next/content/docs/index.mdx`),Se()),y($(e,`web/next/content/blog/index.mdx`),we(a)),y($(e,`web/next/content/blog/hello-world.mdx`),Te(a)),y($(e,`web/next/content/console/docs/index.mdx`),Ce()),y($(e,`web/next/docs.config.ts`),Ee()),y($(e,`web/next/public/.gitkeep`),``),y($(e,`web/next/src/app/page.tsx`),be()),y($(e,`README.md`),xe(t))},Ke=`web/next/src/lib/marketing/fonts.ts`,qe=e=>_($(e,Ke)),Je=(e,t=!1)=>{let n=$(e,`web/next/src/lib/fonts.ts`),r=$(e,Ke),i=$(e,`web/next/src/components/common/navbar.tsx`);if(ee(i,We),_(r)&&!t)throw Error(`web/next/src/lib/marketing/fonts.ts survived the fork strip (add web/next/src/lib/marketing/ to .gitpickignore).`);if(_(n)&&v(n).includes(`fonts/marketing/`))throw Error(`fonts.ts references fonts/marketing/; author-only marketing fonts must live in the fork-excluded web/next/src/lib/marketing/, not the shared fonts.ts.`);if(_(i)&&/href:\s*["']\/hire["']/.test(v(i)))throw Error(`common/navbar.tsx still has the /hire entry after fixDangling (regex drift). Update packages/cli/src/convert.ts.`)},Ye=(e,t)=>{for(let[n,r]of[[`web/next`,t],[`api/hono`,`api.${t}`]]){let t=$(e,n,`package.json`),i=w(t),a=i.portless;if(!a||typeof a!=`object`||Array.isArray(a))throw Error(`${n}/package.json has no "portless" object to rebrand (the dev-URL setup drifted). Update packages/cli/src/convert.ts.`);let o=a;o.name=r,T(t,i)}},Xe=e=>{let t=w($(e,`package.json`)).name;t&&Ye(e,X(t))},Ze=(e,t,n)=>{y($(e,`packages/config/src/site.ts`),ye(t,n));let r=X(t.name),i=$(e,`package.json`),a=w(i);a.name=r,a.version=`0.0.0`;for(let e of E)delete a[e];T(i,a),Ye(e,r)},Qe=(e,t,n=H)=>{Ue(e),Ge(e,t),Je(e),Ze(e,t,n),Ie(e,t),Le(e,t)};export{C as A,ue as C,ae as D,se as E,T as F,g as I,w as M,b as N,S as O,y as P,oe as S,ce as T,_e as _,J as a,A as b,Ve as c,Pe as d,H as f,z as g,R as h,Xe as i,v as j,_ as k,Be as l,ge as m,Je as n,Re as o,me as p,qe as r,He as s,Qe as t,ze as u,N as v,M as w,k as x,O as y};
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./convert-DjNN2nhd.mjs";export{e as convertRepo};
1
+ export{t as convertRepo}from"./convert-D5950liy.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zerostarter",
3
- "version": "0.1.38-canary.1",
3
+ "version": "0.1.38",
4
4
  "description": "Go from zero to a production-ready SaaS, rebranded and ready to ship.",
5
5
  "keywords": [
6
6
  "cli",
@@ -1,161 +0,0 @@
1
- import{delimiter as e,dirname as t,isAbsolute as n,join as r,relative as i,resolve as a,sep as o}from"node:path";import{existsSync as s,mkdirSync as c,readFileSync as l,readdirSync as u,rmSync as d,writeFileSync as f}from"node:fs";import{createHash as p}from"node:crypto";import{spawn as m}from"node:child_process";import{access as h}from"node:fs/promises";const g=e=>{let t=[],n=[],r=!1;for(let i of e.split(`
2
- `)){let e=i.trim();if(e){if(!r&&e.startsWith(`# PRESERVE_ON_SYNC`)){n=e.slice(18).replace(/^\s*-\s*/,``).split(`,`).map(e=>e.trim()).filter(Boolean),r=!0;continue}e.startsWith(`#`)||t.push(e)}}return{excludes:t,preserve:n}},_=e=>s(e),v=e=>l(e,`utf8`),y=(e,n)=>{c(t(e),{recursive:!0}),f(e,n)},b=e=>{d(e,{force:!0,recursive:!0})},x=/* @__PURE__ */ new Set([`node_modules`,`.next`,`.turbo`,`dist`]),S=(e,t=!0)=>{for(let n of u(e,{withFileTypes:!0})){let i=r(e,n.name);if(n.name===`.git`){if(t)continue;d(i,{force:!0,recursive:!0});continue}n.isDirectory()?x.has(n.name)?d(i,{force:!0,recursive:!0}):(S(i,!1),u(i).length===0&&d(i,{force:!0,recursive:!0})):n.name.startsWith(`.env`)||d(i,{force:!0})}},C=e=>{let t=[];for(let n of u(e,{withFileTypes:!0})){if(n.name===`.git`||x.has(n.name))continue;let i=r(e,n.name);n.isDirectory()?t.push(...C(i)):n.name===`package.json`&&t.push(i)}return t},w=e=>JSON.parse(v(e)),T=(e,t)=>{y(e,`${JSON.stringify(t,null,2)}\n`)},ee=(e,t)=>{if(!s(e))return!1;let n=v(e),r=n.replace(t,``);return r!==n&&(f(e,r),!0)},E=[`homepage`,`bugs`,`license`,`author`,`repository`,`funding`],te=[`name`,`version`,...E],ne=(e,t)=>{let n={...e,...t};return Object.keys(n).length>0?n:void 0},re=(e,t)=>{let n=Array.isArray(e)?e:[],r=Array.isArray(t)?t:[];return n.length||r.length?[.../* @__PURE__ */ new Set([...r,...n])]:void 0},ie=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`,`resolutions`,`catalog`,`scripts`,`overrides`],ae=(e,t,n)=>{let r={...t};for(let n of Object.keys(e))n in t||(r[n]=e[n]);for(let n of ie){let i=ne(e[n],t[n]);i&&(r[n]=i)}let i=re(e.workspaces,t.workspaces);if(i&&(r.workspaces=i),n)for(let t of te)t in e?r[t]=e[t]:delete r[t];return r},D=(e,t,n=process.stdout)=>r=>n.isTTY?`\x1b[${e}m${r}\x1b[${t}m`:r,O=D(`36`,`39`),oe=D(`32`,`39`),se=D(`33`,`39`),k=D(`90`,`39`),A=D(`2`,`22`),ce=D(`31`,`39`,process.stderr),le=D(`2`,`22`,process.stderr),ue=D(`38;5;208`,`39`),j=[`◇`,`◆`],M=(e,t)=>{let n=(e%j.length+j.length)%j.length;return`${O(j[n])} ${t}`},N={barStart:`┌`,bar:`│`,barEnd:`└`,active:`◆`,submit:`◇`,radioOn:`●`,radioOff:`○`,checkboxOn:`◼`,checkboxOff:`◻`,warn:`▲`,error:`■`,barH:`─`,cornerTR:`╮`,connectL:`├`,cornerBL:`╰`,cornerBR:`╯`};var P=class extends Error{constructor(...e){super(...e),this.name=`SubprocessError`,this.stdout=``,this.stderr=``}};const F=[`.exe`,`.com`],I=e=>e.replaceAll(/([()\][%!^"`<>&|;, *?])/g,`^$1`),de=e=>I(I(`"${e.replaceAll(/(\\*)"/g,`$1$1\\"`).replace(/(\\*)$/,`$1$1`)}"`)),fe=async(t,n,r)=>{if(F.some(e=>t.toLowerCase().endsWith(e)))return!0;let i=(r.PATH||r.Path||``).split(e).filter(Boolean).map(e=>e.replace(/^"(.*)"$/,`$1`));try{return await Promise.any([n,...i].flatMap(e=>F.map(n=>h(`${a(e,t)}${n}`)))),!0}catch{return!1}},pe=async(e,t,n,r=process.platform===`win32`)=>{let i=n.cwd?String(n.cwd):`.`,a=n.env||process.env;return r&&!n.shell&&!await fe(e,i,a)?[I(e),t.map(de),{...n,shell:!0}]:[e,t,n]},L=async(e,t,n,r)=>{let i=[e,...t].join(` `),[a,o,s]=await pe(e,t,n);s.shell&&o.length>0&&(a=[a,...o].join(` `),o=[]);let c=m(a,o,s),l=``,u=``;return new Promise((e,t)=>{let n=(e,n,r)=>{let i=new P(e,r?{cause:r}:void 0);i.stdout=l,i.stderr=u,i.exitCode=n,t(i)},a=e=>{e.code!==`ERR_STREAM_PREMATURE_CLOSE`&&e.code!==`EPIPE`&&n(`Command failed: ${i}`,void 0,e)};c.stdout&&(c.stdout.setEncoding(`utf8`),c.stdout.on(`data`,e=>{l+=e,r?.(e)}),c.stdout.on(`error`,a)),c.stderr&&(c.stderr.setEncoding(`utf8`),c.stderr.on(`data`,e=>{u+=e,r?.(e)}),c.stderr.on(`error`,a)),c.on(`error`,e=>n(`Command failed: ${i}`,void 0,e)),c.on(`close`,(t,r)=>{if(r)return n(`Command was terminated with ${r}: ${i}`);if(t!==0)return n(`Command failed with exit code ${t}: ${i}`,t??void 0);e({stdout:l,stderr:u})})})},R=async(e,t,n)=>{let{stdout:r}=await L(e,t,{cwd:n,stdio:[`ignore`,`pipe`,`pipe`]});return r},z=async(e,t,n)=>{await L(e,t,{cwd:n,stdio:`inherit`})},me=async(e,t)=>{try{return await L(e,t,{stdio:`ignore`}),!0}catch{return!1}},he=/* @__PURE__ */ RegExp(`\x1B\\[[0-9;?]*[a-zA-Z]`,`g`),B=e=>e.replace(he,``),V=/* @__PURE__ */ new WeakSet,ge=e=>{if(process.stderr.write(`\n ${ce(e instanceof Error?e.message:String(e))}\n`),!(e instanceof P)||V.has(e))return;let t=(e.stderr||e.stdout||``).trim();if(!t)return;let n=B(t).split(`
3
- `).map(e=>e.trimEnd()).filter(Boolean).slice(-12);for(let e of n)process.stderr.write(` ${le(e)}\n`)},_e=async(e,t,n)=>{let r=process.stdout,i=n.label??``;if(!r.isTTY){i&&r.write(` ${O(N.active)} ${i}\n`),await z(e,t,n.cwd);return}let a=n.lines??3,o=[],s=0,c=0,l=``,u=``,d=()=>(r.columns||80)-1,f=e=>{r.write(e?`\x1B[?7h`:`\x1B[?7l`)},p=()=>{c>0&&(r.write(`[${c}A`),c=0)},m=()=>{p();let e=0;r.write(` ${M(s,i)}\n`),e++;for(let t of o.slice(-a))r.write(` ${k(N.bar)} ${A(t.slice(0,Math.max(0,d()-5)))}\n`),e++;c=e},h=e=>{u+=e,l+=e;let t=l.split(`
4
- `);l=t.pop()??``;for(let e of t)o.push(B(e).replace(/\r/g,``).replace(/\t/g,` `).trimEnd()),m()};m(),f(!1);let g=()=>{f(!0),process.exit(130)};process.once(`SIGINT`,g);let _=setInterval(()=>{s+=1,m()},400),v=()=>{clearInterval(_),process.removeListener(`SIGINT`,g)};try{await L(e,t,{cwd:n.cwd,stdio:[`ignore`,`pipe`,`pipe`]},h)}catch(e){throw v(),p(),f(!0),r.write(u),e&&typeof e==`object`&&V.add(e),e}v(),p(),f(!0),r.write(` ${O(N.active)} ${n.done??i}\n`);for(let e of o.slice(-a))r.write(` ${k(N.bar)} ${A(e.slice(0,Math.max(0,d()-5)))}\n`)},H={allowlist:!1,apiDocs:!0,blog:!0,docs:!0,internalDocs:!0,waitlist:!1},ve=e=>`// Optional surfaces a fork enables or disables. Typed boolean (not \`as const\`) so a fork can flip them and the runtime gates are not dead code. Off means the routes 404 and the links, nav, sitemap, llms, and search drop the surface. waitlist off makes the home a plain landing page.
5
- export const features = {
6
- allowlist: ${e.allowlist},
7
- apiDocs: ${e.apiDocs},
8
- blog: ${e.blog},
9
- docs: ${e.docs},
10
- internalDocs: ${e.internalDocs},
11
- waitlist: ${e.waitlist},
12
- }
13
-
14
- export type Feature = keyof typeof features`,ye=({name:e},t=H)=>{let n=e.charAt(0).toUpperCase()+e.slice(1);return`// Brand identity for this app: the single source a fork edits to rebrand. web reads it via lib/config.ts.
15
- export const site = {
16
- name: ${JSON.stringify(n)},
17
- description: ${JSON.stringify(`${n} is just getting started. Tell its story here.`)},
18
- tagline: "Your tagline, ready when you are.",
19
- social: {
20
- discord: "",
21
- github: "",
22
- x: "",
23
- },
24
- // Local-only dev agent identity (api/hono agents router).
25
- agent: {
26
- name: "LocalAgent",
27
- email: "agent@local.host",
28
- },
29
- // Injectable long-form text blocks. A product sets its own, or leaves them empty.
30
- apiReferenceDescription: "",
31
- llmsFullPreamble: "",
32
- } as const
33
-
34
- export type Site = typeof site
35
-
36
- ${ve(t)}
37
- `},be=()=>`import { features, site } from "@packages/config/site"
38
- import { redirect } from "next/navigation"
39
-
40
- // Fresh fork: the waitlist capture when the waitlist feature is on, otherwise a plain landing page. Replace this with your real home when ready.
41
- export default function Home() {
42
- if (features.waitlist) redirect("/waitlist")
43
-
44
- return (
45
- <main className="flex min-h-svh flex-col items-center justify-center p-8 text-center">
46
- <div className="mx-auto flex w-full max-w-xl flex-col items-center">
47
- <h1 className="mb-4 text-5xl font-bold tracking-tight sm:text-6xl">{site.name}</h1>
48
- <p className="text-muted-foreground max-w-md text-lg">{site.tagline}</p>
49
- </div>
50
- </main>
51
- )
52
- }
53
- `,U=()=>`# AGENTS.md
54
-
55
- Guidance for AI coding agents working in this repository.
56
-
57
- ## Instructions
58
-
59
- - ALWAYS: Use \`@/\` for imports, and follow the \`design\` skill for UI and styling conventions.
60
- - ALWAYS: Keep documentation in sync with every change.
61
- - NEVER: Include "Co-authored-by" in commit messages.
62
- - NEVER: Use em-dashes (the long dash, U+2014) in code, comments, docs, or copy. Regular hyphens are fine; for a pause or aside, use a comma, colon, or period.
63
-
64
- ## Skills
65
-
66
- Skills live in \`.agents/skills\` (symlinked to \`.claude/skills\` and \`.github/skills\`, so every agent tool reads the same files). Each is a \`SKILL.md\` with a \`description\` trigger and a literal procedure. Start with \`codebase-map\` to orient, then load the task skill that fits.
67
-
68
- These tables are generated from each skill's own description by \`bun .github/scripts/skills-manager.ts\`, which a pre-commit hook runs for you. **Custom** skills are maintained here; **vendored** skills are copied verbatim from an upstream project (re-vendor to update, do not hand-edit).
69
-
70
- **Custom**
71
-
72
- <!-- skills:custom -->
73
-
74
- <!-- /skills:custom -->
75
-
76
- **Vendored** (upstream, copied verbatim)
77
-
78
- <!-- skills:vendored -->
79
-
80
- <!-- /skills:vendored -->
81
- `,xe=({name:e})=>`# ${e.charAt(0).toUpperCase()+e.slice(1)}
82
-
83
- Built on top of [ZeroStarter](https://zerostarter.dev).
84
-
85
- ## Development
86
-
87
- \`\`\`bash
88
- bun run dev
89
- \`\`\`
90
-
91
- This serves named \`.localhost\` dev URLs via portless (\`bunx portless list\` shows them); \`PORTLESS=0 bun run dev\` uses fixed ports instead (web \`:3000\`, api \`:4000\`).
92
- `,Se=()=>`---
93
- slug: /docs
94
- title: Introduction
95
- description: Documentation.
96
- ---
97
-
98
- # Introduction
99
-
100
- This is your documentation home. Start writing, this page is yours.
101
- `,Ce=()=>`---
102
- slug: /console/docs
103
- title: Introduction
104
- description: Internal documentation.
105
- ---
106
-
107
- # Introduction
108
-
109
- Your team's internal docs live here.
110
- `,we=e=>`---
111
- title: Blog
112
- description: Latest articles and updates
113
- createdAt: ${e}
114
- ---
115
-
116
- ## Recent Posts
117
-
118
- <BlogPostList />
119
- `,Te=e=>`---
120
- title: Hello World
121
- description: The first post on your new blog.
122
- createdAt: ${e}
123
- publishedAt: ${e}
124
- ---
125
-
126
- ## Hello World
127
-
128
- Your very first post. Replace it with something worth reading.
129
- `,Ee=()=>`import type { DocsConfig } from "./src/lib/docs"
130
-
131
- const docsConfig = {
132
- docs: {
133
- "Getting Started": [
134
- {
135
- "/docs": {
136
- title: "Introduction",
137
- description: "Documentation.",
138
- },
139
- },
140
- ],
141
- },
142
- console: {
143
- "Getting Started": [
144
- {
145
- "/console/docs": {
146
- title: "Introduction",
147
- description: "Internal documentation.",
148
- },
149
- },
150
- ],
151
- },
152
- } satisfies DocsConfig
153
-
154
- export default docsConfig
155
- `,W=`https://github.com/nrjdalal/zerostarter`,G=`.agents/skills/.sync.json`,K=`main`,q=`AGENTS.md`,J=()=>({adopted:[],customized:[],forkOwned:[],unverified:[]}),Y=e=>p(`sha256`).update(e.replace(/\r\n/g,`
156
- `)).digest(`hex`).slice(0,12),X=e=>e.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``)||`app`,Z=(e,t,n)=>e.replaceAll(`ZeroStarter`,()=>n).replace(/(?<!bunx )zerostarter(?! scaffolding CLI)/g,t),De=`> Synced from ${W}.`,Oe=()=>`> [!CAUTION]\n${De} Customize this skill or remove this note to stop syncing.`,ke=e=>e.replace(/^https?:\/\/github\.com\//,``).replace(/\/+$/,``),Ae=ke(W),je=e=>{let t=e.split(`
157
- `);if(t[0]===void 0||t[0].trim()!==`---`)return``;for(let e of t.slice(1)){if(e.trim()===`---`)break;if(e.startsWith(`source:`))return e.slice(7).trim()}return``},Me=e=>u(e,{withFileTypes:!0}).filter(t=>t.isDirectory()&&_(r(e,t.name,`SKILL.md`))).map(e=>e.name).sort(),Ne=e=>{let t=r(e,G);if(!_(t))return{};try{return w(t)}catch{return{}}},Pe=e=>{let t=r(e,`.agents/skills`),n=/* @__PURE__ */ new Map;if(!_(t))return n;for(let e of Me(t))n.set(e,v(r(t,e,`SKILL.md`)));return n},Fe=(e,t,n,r,i=!1)=>{let a=e.replace(/\r\n/g,`
158
- `).split(`
159
- `),o=a.indexOf(`---`),s=a.indexOf(`---`,o+1);if(o!==0||s===-1)throw Error(`.agents/skills/${r}/SKILL.md has no frontmatter to reconcile (the skill shape drifted). Update packages/cli/src/skills.ts.`);let c=je(e),l=i||c===``||c===`local`?W:c,u=a.slice(o+1,s).map(e=>e.startsWith(`source:`)?`source: ${l}`:Z(e,t,n));u.some(e=>e.startsWith(`source:`))||u.push(`source: ${l}`);let d=Z(a.slice(s+1).join(`
160
- `),t,n).replace(/^\n+/,``),f=l===W?`${Oe()}\n\n`:``;return`---\n${u.join(`
161
- `)}\n---\n\n${f}${d}`},Ie=(e,t,n)=>{let i=r(e,`.agents/skills`),a=J();if(!_(i))return a;let o=X(t.name),s=Ne(e),c={};for(let e of Me(i)){let l=r(i,e,`SKILL.md`),u=v(l),d=Fe(u,o,t.name,e),f=n===void 0?void 0:n.get(e),p=s[e];if(f!==void 0){let n=je(f),r=t=>{y(l,f),t.push(e),p&&(c[e]=p)},i=ke(n);if(n!==``&&i!==Ae){r(a.forkOwned);continue}if(i===Ae&&!f.includes(De)){r(a.forkOwned);continue}if(p){if(p.written!==Y(f)){r(a.customized);continue}}else Y(f)!==Y(d)&&Y(f)!==Y(Fe(u,o,t.name,e,!0))&&a.unverified.push(e)}y(l,d),c[e]={ref:K,upstream:Y(u),written:Y(d)},a.adopted.push(e)}return s[`AGENTS.md`]&&(c[q]=s[q]),T(r(e,G),c),a},Q=e=>e.replace(/(<!-- skills:(custom|vendored) -->)[\s\S]*?(<!-- \/skills:\2 -->)/g,`$1$3`),Le=(e,t,n)=>{let i=r(e,q),a=r(e,G),o=Ne(e),s=X(t.name),c=(e,t)=>(y(i,t),o[q]={ref:K,upstream:Y(e),written:Y(Q(t))},T(a,o),`adopted`);if(n===void 0){if(!_(i))return c(U(),U());let e=v(i);return c(e,Z(e,s,t.name))}let{before:l,upstream:u}=n;if(u===void 0||u===l)return`absent`;if(l!==void 0){let e=o[q];if(!(e?e.written===Y(Q(l)):Y(Q(l))===Y(Q(U()))))return y(i,l),e?`customized`:`forkOwned`}return c(u,Z(u,s,t.name))},Re=e=>{let t=r(e,`AGENTS.md`);if(!_(t))return!1;let n=v(t);return!n.includes(`<!-- skills:custom -->`)||!n.includes(`<!-- skills:vendored -->`)},ze=async e=>{if(_(r(e,`.github/scripts/skills-manager.ts`)))try{await R(`bun`,[`.github/scripts/skills-manager.ts`],e)}catch{}},Be=(e,t)=>{let n=w(r(e,`package.json`)).name;return n?Ie(e,{name:n},t):J()},Ve=(e,t)=>{let n=w(r(e,`package.json`)).name;return n?Le(e,{name:n},t):`absent`},He=e=>{let t=r(e,q);return _(t)?v(t):void 0},$=(e,...t)=>r(e,...t),Ue=e=>{let t=$(e,`.gitpickignore`);if(!_(t))return;let s=a(e),c=(e,t)=>{throw Error(`.gitpickignore entry "${e}" ${t}; the in-place converter only removes literal paths under the root.`)},l=g(v(t)).excludes.map(e=>{/[*?![\]]/.test(e)&&c(e,`is not a literal path (a glob or negation would diverge from gitpick's fetch)`);let t=i(s,a(s,e));return(n(e)||!t||t===`..`||t.startsWith(`..${o}`)||n(t))&&c(e,`is not inside the project`),r(s,t)});for(let e of l)b(e);b(t)},We=/[ \t]*\{[^}\r\n]*href:[ \t]*["']\/hire["'][^}\r\n]*\},?[ \t]*\r?\n/,Ge=(e,t)=>{let n=/* @__PURE__ */ new Date,r=n.toISOString().slice(0,10),i=[n.getFullYear(),n.getMonth()+1,n.getDate()].map(e=>String(e).padStart(2,`0`)).join(`-`),a=i<r?i:r;y($(e,`web/next/content/docs/index.mdx`),Se()),y($(e,`web/next/content/blog/index.mdx`),we(a)),y($(e,`web/next/content/blog/hello-world.mdx`),Te(a)),y($(e,`web/next/content/console/docs/index.mdx`),Ce()),y($(e,`web/next/docs.config.ts`),Ee()),y($(e,`web/next/public/.gitkeep`),``),y($(e,`web/next/src/app/page.tsx`),be()),y($(e,`README.md`),xe(t))},Ke=`web/next/src/lib/marketing/fonts.ts`,qe=e=>_($(e,Ke)),Je=(e,t=!1)=>{let n=$(e,`web/next/src/lib/fonts.ts`),r=$(e,Ke),i=$(e,`web/next/src/components/common/navbar.tsx`);if(ee(i,We),_(r)&&!t)throw Error(`web/next/src/lib/marketing/fonts.ts survived the fork strip (add web/next/src/lib/marketing/ to .gitpickignore).`);if(_(n)&&v(n).includes(`fonts/marketing/`))throw Error(`fonts.ts references fonts/marketing/; author-only marketing fonts must live in the fork-excluded web/next/src/lib/marketing/, not the shared fonts.ts.`);if(_(i)&&/href:\s*["']\/hire["']/.test(v(i)))throw Error(`common/navbar.tsx still has the /hire entry after fixDangling (regex drift). Update packages/cli/src/convert.ts.`)},Ye=(e,t)=>{for(let[n,r]of[[`web/next`,t],[`api/hono`,`api.${t}`]]){let t=$(e,n,`package.json`),i=w(t),a=i.portless;if(!a||typeof a!=`object`||Array.isArray(a))throw Error(`${n}/package.json has no "portless" object to rebrand (the dev-URL setup drifted). Update packages/cli/src/convert.ts.`);let o=a;o.name=r,T(t,i)}},Xe=e=>{let t=w($(e,`package.json`)).name;t&&Ye(e,X(t))},Ze=(e,t,n)=>{y($(e,`packages/config/src/site.ts`),ye(t,n));let r=X(t.name),i=$(e,`package.json`),a=w(i);a.name=r,a.version=`0.0.0`;for(let e of E)delete a[e];T(i,a),Ye(e,r)},Qe=(e,t,n=H)=>{Ue(e),Ge(e,t),Je(e),Ze(e,t,n),Ie(e,t),Le(e,t)};export{C as A,ue as C,ae as D,se as E,T as F,g as I,w as M,b as N,S as O,y as P,oe as S,ce as T,_e as _,J as a,A as b,Ve as c,Pe as d,H as f,z as g,R as h,Xe as i,v as j,_ as k,Be as l,ge as m,Je as n,Re as o,me as p,qe as r,He as s,Qe as t,ze as u,N as v,M as w,k as x,O as y};