@turboforge/sync 0.0.0 → 0.0.1

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.
@@ -0,0 +1,6 @@
1
+ import{exec as U,execFile as _}from"child_process";import{randomUUID as oe}from"crypto";import{realpathSync as J}from"fs";import{access as M,readFile as G,rename as ae,rm as ce,writeFile as le}from"fs/promises";import{dirname as W,join as q,parse as B,resolve as Y}from"path";import{fileURLToPath as Z}from"url";import{promisify as k}from"util";var d=k(U),y=k(_),A=async e=>{try{return await M(e),!0}catch(t){if(t.code==="ENOENT")return!1;throw t}},h=new Map,E=200,ue=async(e,t)=>{let n=Y(e),r=`${n}:${[...t].sort().join(",")}`;if(h.has(r))return h.get(r);let o=n,{root:i}=B(o);for(;;){for(let c of t)if(await A(q(o,c)))return h.set(r,o),h.size>E&&h.clear(),o;if(o===i)break;o=W(o)}return h.set(r,null),h.size>E&&h.clear(),null},fe=async(e,t={})=>{try{let n=await G(e,"utf-8");return JSON.parse(n)}catch(n){if(n.code==="ENOENT")return null;if(t.strict)throw n;return null}},de=async(e,t={})=>{if(!await A(e))return null;try{let n=await import("./jiti-D4HPEZZY.mjs"),o=(n.createJiti?n.createJiti(process.cwd()):n.default(process.cwd()))(e);return o.default??o}catch{try{let n=await import(e);return n.default??n}catch(n){if(t.strict)throw/\.(ts|mts)$/.test(e)?new Error(`Failed to load TypeScript config at ${e}. Install 'jiti' to load TS configs. Original error: ${n}`):n;return null}}},S=(e,t)=>{if(typeof e!="object"||e===null||typeof t!="object"||t===null||Array.isArray(e)&&Array.isArray(t))return t;let n={...e};for(let r of Object.keys(t))r==="__proto__"||r==="constructor"||r==="prototype"||Object.hasOwn(t,r)&&(n[r]=r in e?S(e[r],t[r]):t[r]);return n};var he=()=>J(process.argv[1])===Z(import.meta.url);import{access as ve,readFile as X,writeFile as K}from"fs/promises";import{resolve as Le}from"path";import{createWriteStream as H}from"fs";import V from"os";var w="\x1B[",L={gray:e=>`${w}90m${e}${w}39m`,blue:e=>`${w}34m${e}${w}39m`,yellow:e=>`${w}33m${e}${w}39m`,red:e=>`${w}31m${e}${w}39m`},F={debug:20,info:30,warn:40,error:50},N={debug:L.gray,info:L.blue,warn:L.yellow,error:L.red},T=e=>{let t=F[e.level],n=e.logFormat??"text",r=e.name,o=r?{debug:`${r}:DEBUG`,info:`${r}:INFO`,warn:`${r}:WARN`,error:`${e.name}:ERROR`}:{debug:"DEBUG",info:"INFO",warn:"WARN",error:"ERROR"},i=null,c=!1,m=process.stdout.isTTY&&!process.env.NO_COLOR||!!process.env.FORCE_COLOR;if(e.logFile)try{i=H(e.logFile,{flags:"a"}),i.on("error",()=>{i=null})}catch{i=null}let p=()=>{if(!c&&(c=!0,i)){try{i.end()}catch{}i=null}};process.once("exit",p),process.once("SIGINT",()=>{p(),process.exit(0)}),process.once("SIGTERM",()=>{p(),process.exit(0)});let x=process.pid,v=V.hostname(),l=(a,...s)=>{if(F[a]<t)return;let g=new Date().toISOString(),u=s.map(String).join(" "),f=n==="json"?JSON.stringify({ts:g,level:a,message:u,pid:x,hostname:v,name:r}):`[${g}] [${o[a]}] ${u}`,b=m&&N[a]?N[a](f):f;if((a==="warn"||a==="error"?process.stderr:process.stdout).write(`${b}
2
+ `),i)try{i.write(`${f}
3
+ `)}catch{i=null}};return{debug:(...a)=>l("debug",...a),info:(...a)=>l("info",...a),warn:(...a)=>l("warn",...a),error:(...a)=>l("error",...a),close:p}};import{resolveConflicts as j}from"git-json-resolver";var D=()=>Promise.all([d("git diff --quiet"),d("git diff --cached --quiet")]);var C=e=>e.replace(/[^a-zA-Z0-9._/-]/g,""),I=e=>{let t=e.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9_-]/g,"");if(!t||!/^[a-zA-Z0-9_]/.test(t)||t.startsWith("-"))throw new Error(`Invalid remote name: "${e}". Remote names may only contain letters, numbers, underscore, and hyphen, and cannot start with '-'.`);return t},$=e=>e.replace(/[\r\n]/g,""),O=async({remoteName:e,baseRef:t,targetRef:n,exclusions:r,logger:o,maxRetries:i=3,errorLogs:c=[]},m=0)=>{if(m>i){o.warn(`Max patch recursion reached (${i}), stopping`);return}let p=`git diff ${t} ${e}/main -- ${r.join(" ")} .`;o.debug(`Running: ${p}`);let{stdout:x}=await y("git",["diff",t,`${e}/${n}`,"--",...r,"."],{encoding:"utf8"});await K(".template.patch",x),o.debug(`Patch written to .template.patch (${x.length} chars)`);try{o.debug("Applying patch with 3-way merge"),await d("git apply --3way --ignore-space-change --ignore-whitespace .template.patch",{encoding:"utf8"}),o.debug("Patch applied successfully")}catch(v){let l=v.stderr?.split(`
4
+ `).filter(a=>a.startsWith("error"));o.debug(`Patch failed with ${l.length} errors`),l.forEach(a=>{let s=a.split(":")[1]?.trim();s&&(r.push(`:!${s}`),o.debug(`Added to exclusions: ${$(s)}`))}),c.push("Applied patch with errors: "),c.push({errorLines:l,exclusions:r}),c.push("^^^---Applied patch with errors"),l.length&&await O({remoteName:e,baseRef:t,targetRef:n,exclusions:r,logger:o,maxRetries:i,errorLogs:c},m+1)}},z=async e=>{await j({include:["package.json"],defaultStrategy:["merge","theirs"],rules:{name:["ours"],"devDependencies.*":["ignore-removed","theirs"],"dependencies.*":["ignore-removed","theirs"]},debug:e}),await j({include:["**/package.json"],exclude:["package.json","**/dist/**","**/.next/**"],defaultStrategy:["merge","non-empty","ours"],rules:{"devDependencies.*":["semver-max"],"dependencies.*":["semver-max"]},loggerConfig:{logDir:".logs2",levels:{stdout:[]}},plugins:["git-json-resolver-semver"],pluginConfig:{"git-json-resolver-semver":{preferValid:!0}},includeNonConflicted:!0,debug:e})},Oe=async e=>{try{let c=await X(e,"utf8");return JSON.parse(c).lastSyncedCommit}catch{}let[{stdout:t},{stdout:n}]=await Promise.all([d("git log --reverse --format=%ai | head -n 1",{encoding:"utf8"}),d("git log --format=%H::%ai template/main",{encoding:"utf8"})]),r=new Date(t.trim()),i=n.trim().split(`
5
+ `).map(c=>{let[m,p]=c.split("::");return{hash:m,date:new Date(p?.trim())}}).reverse().find(c=>c.date>=r);if(i)return console.info("Applying changes from ",i.hash," dated ",i.date),i.hash};import{writeFile as Q}from"fs/promises";var ee={logLevel:"info",dryRun:!1,templateUrl:"https://github.com/turboforge/forge-template.git",excludePaths:[],remoteName:"template",maxPatchRetries:3,backupDir:".forge-backup",skipCleanCheck:!1,targetRef:"main",metaFile:".forge-meta.json",baseRef:"",postSync:["pnpm install","pnpm biome check --write --no-errors-on-unmatched $(git diff --cached --name-only --diff-filter=ACM | grep -E '\\.(ts|tsx|js|json)$' || true)"]},te=[],Fe=async e=>{let{logLevel:t,skipCleanCheck:n,dryRun:r,remoteName:o,templateUrl:i,backupDir:c,baseRef:m,excludePaths:p,targetRef:x,metaFile:v,postSync:l,maxPatchRetries:a}=S(ee,e),s=T({level:t});if(!m){s.error("\u274C Error: Base ref is required");return}if(n)s.info("Skipping git clean check");else try{await D(),s.info("Git tree is clean")}catch{s.error("\u274C Error: Please commit or stash your changes before upgrading.");return}r&&s.info("Dry run mode - no changes will be applied");let g=I(o);try{await Promise.all([y("git",["remote","add",g,i]),d(`rm -rf ${c}`)])}catch{s.debug(`${$(g)} remote already exists`)}finally{s.debug(`Added ${$(g)} remote: ${$(i)}`)}try{await y("git",["fetch",g]),s.debug(`Fetched latest changes from ${$(g)}`);let u=C(m),f=C(x),b=[...p].map(R=>`:!${R}`);if(s.debug(`Base exclusions: ${b.length} items`),s.debug(`Generating patch from ${u} to ${f}`),s.debug(`Total exclusions: ${b.length}`),r){let{stdout:R}=await y("git",["diff",u,`${g}/${f}`,"--",...b,"."],{encoding:"utf8"});s.info("\u{1F4CB} Patch preview:"),s.info(R||"No changes to apply");return}await O({remoteName:g,baseRef:u,targetRef:f,exclusions:b,logger:s,maxRetries:a,errorLogs:te});let{stdout:P}=await y("git",["rev-parse",`${g}/${f}`],{encoding:"utf8"});await Q(v,JSON.stringify({lastSyncedCommit:P.trim(),baseRef:u,targetRef:f,generatedAt:new Date().toISOString()},null,2)),await z(t==="debug"),console.log("\u2705 Upgrade applied successfully."),r||(s.info("Running post-sync commands..."),s.info(l.join(`
6
+ `)),await Promise.all(l.map(R=>d(R))))}catch(u){console.error("\u274C Upgrade failed:",u)}try{await y("git",["remote","remove",g])}catch{}};export{ue as a,fe as b,de as c,S as d,he as e,Oe as f,ee as g,Fe as h};
package/dist/cli.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { ForgeSyncOptions } from './index.mjs';
3
+ import '@turboforge/cli-kit';
3
4
 
4
5
  interface CliOptions extends ForgeSyncOptions {
5
6
  help?: boolean;
package/dist/cli.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { ForgeSyncOptions } from './index.js';
3
+ import '@turboforge/cli-kit';
3
4
 
4
5
  interface CliOptions extends ForgeSyncOptions {
5
6
  help?: boolean;