bisgit 0.8.0 → 0.8.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.
package/README.md CHANGED
@@ -43,4 +43,8 @@ Run `gi` or `bisgit` for full TUI.
43
43
  - `gi exclude` and `gi include` allows you to ignore files locally without modifying the .gitignore file.
44
44
  - `gi remote-default` shows whether the remote default branch is 'main', 'master', etc.
45
45
 
46
+ ## Tips
47
+
48
+ - If using this in VS Code's integrated terminal, I'd recommend disabling `terminal.integrated.stickyScroll.enabled` or adding gi to `terminal.integrated.stickyScroll.ignoredCommands`
49
+
46
50
  I turned many of my git aliases into commands. The original aliases are found this [gist](https://gist.github.com/alexanderdombroski/ddac491daeff48c5f1346ba2960462fa).
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import{b as u,c as X,d as at,e as R,f as h,g as V,h as A,i as N,j as U,k as ct,l as y,m as S}from"./chunk-HKY7QTE6.js";import{a as x,d as w,e as tt,f as W,g as I,h as k,i as et,j as ot,k as rt,m as G,n as C,o as M,p as P,q as it,r as nt,s as F,t as st,w as H,x as L}from"./chunk-7XT4D6II.js";import{a as b,b as s,c as E,d,e as f}from"./chunk-R7DNYVL6.js";import B from"node:path";async function mt(){let t=await M(),e=/^(UU|DU|UD)/;return!!t?.some(o=>e.test(o))}async function O(){let t=await et(),[e,o,n,r,i]=await Promise.all([await x(B.join(t,"MERGE_HEAD")),await x(B.join(t,"rebase-merge")),await x(B.join(t,"rebase-apply")),await x(B.join(t,"CHERRY_PICK_HEAD")),await x(B.join(t,"REVERT_HEAD"))]);return{merge:e,rebaseMerge:o,rebaseApply:n,cherryPick:r,revert:i}}async function lt(){let{merge:t,rebaseMerge:e,rebaseApply:o,cherryPick:n,revert:r}=await O(),i="";if(t)i="merge";else if(e||o)i="rebase";else if(n)i="cherry-pick";else if(r)i="revert";else{let a=await mt()?"Conflicts exist, but likely are from a stash and are not abortable. Resolve them manually.":"Nothing to abort.";console.log(a);return}console.log(`Aborting the ${i}`),await f([i,"--abort"])}async function ft(){await U(),await S(),b("git",["commit","--amend","--no-edit",...u()],{stdio:"inherit",silent:!0,triggerExit:!0})}import{render as re}from"ink";import{render as ee}from"ink";import{Suspense as zt,use as Jt,useEffect as Kt}from"react";import{Text as pt,useApp as Zt}from"ink";import Qt from"ink-spinner";import{jsx as j,jsxs as te}from"react/jsx-runtime";function m(t){let{msg:e}=t;return j(zt,{fallback:te(pt,{children:[j(Qt,{type:"dots"}),"\xA0",e]}),children:j(Xt,{...t})})}function Xt({msg:t,promise:e}){let o=Jt(e),{exit:n}=Zt();return Kt(()=>{n()},[o]),j(pt,{children:`\u2714 ${typeof o=="string"?o:t}`})}import{jsx as oe}from"react/jsx-runtime";async function gt(){let t=process.argv[3],e=process.argv[4]??await w();if(V(t),V(e),t===e)return console.log(`No reason to merge '${t}' into '${e}'`);let o=await tt(t);h(o),ee(oe(m,{msg:"Updating target branch and merging",promise:(async()=>{try{await T(o,t)}catch{console.error(`Error when updating branch ${t} with remote ${o}. Fix divergent branches before merging into ${e}`);return}await w()!==e&&await s(`git switch ${e}`),b("git",["merge",t],{stdio:"inherit",silent:!0})})()}))}async function T(t,e){await G(t,e);let[o,n,r]=await Promise.all([W(t,e),I(t,e),w()]);if(n!==0){if(o===0&&r!==e){await s(`git fetch ${t} ${e}:${e}`);return}if(await s(`git switch ${e}`),o===0){await s(`git merge ${t}/${e}`);return}await f(["merge",`${t}/${e}`],["ignore","ignore","inherit"])}}async function q(){R(),h();let{stdout:t,code:e}=await d("git",["rev-parse","--abbrev-ref","origin/HEAD"]);if(e===0)return ut(t.trim());await s("git remote set-head origin -a");let{stdout:o}=await s("git rev-parse --abbrev-ref origin/HEAD");return ut(o.trim())}async function dt(){let{remote:t,branch:e}=await q();console.log(`Remote default branch is '${t}/${e}'`)}async function ut(t){let e=t.split("/"),o=t.split("/").map((n,r)=>e.slice(0,r+1).join("/"));for(let n of o)if(await rt(n)){let r=t.slice(n.length+1);return{remote:n,branch:r}}throw new Error("Failed to get default remote")}import{jsx as ne}from"react/jsx-runtime";var ie=["master","main","development","lingoport"];async function wt(){await A();let{branch:t,remote:e}=await q();await s(`git switch ${t}`);let o=(async()=>{await f(["fetch","--prune","--prune-tags"]),await T(e,t)})();re(ne(m,{msg:"Fetching and pruning remote references",promise:o})),await o;let n=await st();for(let r of n){if(r===t||ie.includes(r))continue;let{code:i}=await d("git",["diff","--quiet",t,r]);if(i===0){Y(r);continue}let{code:a}=await d("git",["merge-base","--is-ancestor",r,t]);if(a===0){Y(r);continue}let c=await P(r,t),{stdout:l}=await d("git",["merge-tree",c,t,r]);l?.trim()||Y(r)}}function Y(t){f(["branch","-D",t])}import{spawn as se}from"node:child_process";import{createInterface as ae}from"node:readline/promises";async function ht(){R;let e=[...(await ce()).entries()].sort(([,n],[,r])=>r-n).slice(0,25),o=e[0][1].toString().length;console.info(e.map(([n,r])=>`${String(r).padEnd(o)} ${n}:`).join(`
3
+ `))}async function ce(){let{promise:t,resolve:e,reject:o}=Promise.withResolvers(),n=new Map,r=se("git",["log","--all","-M","-C","--name-only","--format=format:"]),i=ae({input:r.stdout,crlfDelay:1/0});return i.on("line",a=>{let c=a.trim();c&&n.set(c,(n.get(c)??0)+1)}),i.on("close",()=>e(n)),r.on("error",o),t}import{render as bt}from"ink";import{Box as me,Text as le,useApp as fe,useInput as pe}from"ink";import ge from"ink-select-input";import{jsx as yt,jsxs as ue}from"react/jsx-runtime";function $t({prompt:t,onSelect:e,items:o}){let{exit:n}=fe();return pe((r,i)=>{i.escape&&n()}),ue(me,{flexDirection:"column",children:[yt(le,{children:t}),yt(ge,{items:o,onSelect:e})]})}import{jsx as Ct}from"react/jsx-runtime";async function Pt(){await S();let t=u()[0];if(!t){let i=(await we()).map(c=>({value:c,label:`${c.name} ${c.email} (${c.commits})`}));bt(Ct($t,{items:i,prompt:"Who assisted in this commit?",onSelect:({value:{name:c,email:l}})=>{xt(c,l.slice(1,-1))}}));return}let e=(async()=>{let r=await de(t);return r.email||(console.error(`Couldn't find an email for ${t}`),process.exit(1)),r})();bt(Ct(m,{msg:"Fetching name and email",promise:e}));let{name:o,email:n}=await e;xt(o,n)}async function de(t){let{stdout:e}=await s(`gh api users/${t}`);return JSON.parse(e.trim())}async function we(){let t=await E('git log --format="%an|<%ae>"'),e=new Map;for(let o of t){let[n,r]=o.split("|"),i=`${n}|${r}`;e.has(i)||e.set(i,{name:n,email:r,commits:0}),e.get(i).commits+=1}return[...e.values()].toSorted((o,n)=>n.commits-o.commits)}async function xt(t,e){f(["commit","--edit","-m","<insert summary>","-m",`Co-authored-by: ${t} <${e}>`])}import{render as z}from"ink";import{isDeepStrictEqual as he}from"node:util";import{jsx as J}from"react/jsx-runtime";async function Rt(){let t=y("Error: missing id of PR to checkout");await A();let e=(async()=>Promise.all([s(`gh co ${t}`),s(`gh pr view ${t} --json baseRefName -q .baseRefName`)]))();z(J(m,{msg:`Checking out pr #${t}`,promise:e}));let[,{stdout:o}]=await e,n=o.trim(),r=(async()=>{await s(`git switch ${n}`),await s("git pull"),await s("git switch -")})();z(J(m,{msg:`Updating ${n} branch merge destination`,promise:r})),await r;let i=(async()=>{let g=await P(n,"HEAD");return await s(`git reset ${g} --soft`),await ye("HEAD")})();z(J(m,{msg:"Creating an editable, explorable, local PR experience",promise:i}));let[a,c]=await Promise.all([i,$e(t)]),{files:l,additions:p,deletions:D}=c;if(he(a,c))return console.info(`Files: ${l}, +${p} -${D}`);console.info("The PR stat doesn't match the local stat."),console.info("LOCAL"),console.table(a),console.info("GITHUB"),console.table(c),console.info("One option to fix (there'll likely be conflicts):"),console.info("1. git stash -u"),console.info(`2. git merge ${n}`),console.info("3. git stash pop")}async function ye(t){let{stdout:e}=await s(`git diff --shortstat ${t}`),o=/(\d+)\s+files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/,n=e.trim().match(o);if(!n)throw new Error(`Couldn't generate short stat for ref(s): ${t}`);let[,r,i,a]=n;return{files:parseInt(r,10),additions:i?parseInt(i,10):0,deletions:a?parseInt(a,10):0}}async function $e(t){let{stdout:e}=await s(`gh pr view ${t} --json deletions,files,additions`),o=JSON.parse(e.trim());return o.files=o.files.length,o}import{spawn as be}from"node:child_process";import{createInterface as xe}from"node:readline/promises";import K from"chalk";async function At(){let t=y("Error: missing target branch argument"),e=await P("HEAD",t),{promise:o,resolve:n,reject:r}=Promise.withResolvers(),i=be("git",["merge-tree",e,"HEAD",t]),a=xe({input:i.stdout,crlfDelay:1/0}),c=!1,l=0;a.on("line",g=>{g=g.trimEnd(),g==="+<<<<<<< .our"?(c=!0,console.info(K.red(g)),l+=1):g==="+>>>>>>> .their"?(c=!1,console.info(K.green(g))):g==="+======="?console.info(K.yellow(g)):c&&console.info(g)}),a.on("close",()=>n(l)),i.on("error",r);let p=await o,D=p?`\u274C ${p} conflicts would occur!`:"\u2705 No conflicts. Safe to merge.";console.info(D)}async function St(){let{merge:t,rebaseMerge:e,rebaseApply:o,cherryPick:n,revert:r}=await O(),i="";if(t)i="merge";else if(e||o)i="rebase";else if(n)i="cherry-pick";else if(r)i="revert";else{console.log("Nothing to continue.");return}console.log(`Continuing the ${i}`),await f([i,"--continue"])}import{appendFileSync as Pe}from"node:fs";import{readFile as Ce}from"node:fs/promises";async function _(t){return(await Ce(t,"utf-8")).split(/\r?\n/).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"))}async function vt(){let t=await k("info/exclude");await N(t);let e=await _(t);u().forEach(o=>{e.includes(o)?console.info(`Already Exists: '${o}'`):(Pe(t,`${o}
4
+ `),console.info(`Added '${o}'`))}),console.info(`
5
+ See file at ${t}`)}async function Dt(){let t=u();if(t[0]){let e=await Re(t[0]);console.info(e.join(`
6
+ `))}else f(["status","--short"])}async function Re(t){return L(t)?await E(`git stash show -p --include-untracked --name-only ${t}`):await E(`git show --name-only --pretty=format:"" ${t}`)}import{spawn as Ae}from"node:child_process";async function Et(){let t=y("Error: missing valid target ref argument");await S();let e=await nt(t);await f(["commit",`--fixup=${e}`]);let n=(await F(`${e}^`,"HEAD",!0)).map(i=>Se(i));(await Promise.all(n)).every(Boolean)||(console.warn("Rebase conflict would occur!"),await s("git reset HEAD~1 --soft"),process.exit(1)),await s(`git rebase -i --autosquash ${e}^`)}async function Se(t){let{stdout:e}=await s(`git diff ${t}^ ${t}`),{promise:o,resolve:n,reject:r}=Promise.withResolvers(),i=Ae("git",["apply","--check","--3way","-q"],{stdio:["pipe","ignore","ignore"]});return i.on("close",a=>{n(a===0)}),i.on("error",r),i.stdin.write(e),i.stdin.end(),o}import{readFile as ve,writeFile as De}from"node:fs/promises";async function kt(){let t=await k("info/exclude");await N(t);let e=await _(t),o=u();o.filter(a=>!e.includes(a)).forEach(a=>console.info(`No match: '${a}'`));let r=(await ve(t,"utf-8")).split(/\r?\n/).map(a=>a.trim()),i=r.filter(a=>!o.includes(a));await De(t,i.join(`
7
+ `)),console.info(`
8
+ Removed ${r.length-i.length} entries from ${t}`)}import{render as Ee}from"ink";import{jsx as qe}from"react/jsx-runtime";async function Bt(){let t=(async()=>{let r=await ke();return await Be(r)})();Ee(qe(m,{msg:"Fetching repo languages",promise:t}));let e=await t,o=Object.values(e).reduce((r,i)=>r+i,0),n=Object.entries(e).map(([r,i])=>`${r}: ${Math.round(i/o*100)}% - ${Te(i)}`);console.log(n.join(`
9
+ `))}async function ke(){let{stdout:t}=await s("gh repo view --json nameWithOwner -q .nameWithOwner");return t.trim()}async function Be(t){let{stdout:e}=await s(`gh api repos/${t}/languages`);return JSON.parse(e.trim())}function Te(t,e=2){if(t===0)return"0 B";let o=1024,n=e<0?0:e,r=["B","KB","MB","GB","TB","PB","EB","ZB","YB"],i=Math.floor(Math.log(t)/Math.log(o));return`${parseFloat((t/Math.pow(o,i)).toFixed(n))} ${r[i]}`}import $ from"chalk";async function Tt(){y();let t=u(),[e,o]=t.filter(r=>r!=="-v"),n=[];if(L(e)?(n.push(...await H(`${e}^3`)),n.push(...await H(`${e}^2`))):n.push(...await H(e,o)),t.includes("-v")){let r={added:"A",modified:"M",deleted:"D",binary:"B"};n.forEach(i=>{let c=`${We(i.changeType)(r[i.changeType])} ${i.file} |`;i.added&&(c+=$.green(` +${i.added}`)),i.deleted&&(c+=$.red(` -${i.deleted}`)),console.info(c)})}else{let r=new Set(n.map(({file:p})=>p)).size,[i,a]=n.reduce((p,{added:D,deleted:g})=>[p[0]+(D??0),p[1]+(g??0)],[0,0]),c=$.green(`+${i}`),l=$.red(`-${a}`);console.info(`${r} files: ${c} ${l}`)}}var We=t=>{switch(t){case"modified":return $.yellow;case"added":return $.green;case"deleted":return $.red;default:return e=>e}};async function qt(){let t=await ot();console.log(t)}import{render as It}from"ink";function Wt(){return new Date().toLocaleString("en-US",{year:"2-digit",month:"2-digit",day:"2-digit",hour:"numeric",minute:"2-digit",hour12:!0}).replace(",","")}async function v(){let t=Wt();await s("git add -A"),await f(["commit","-m",`"WIP ${t}"`])}import{nanoid as Ie}from"nanoid";import Ge from"chalk";import{jsx as Gt}from"react/jsx-runtime";async function Mt(){let{remote:t,branch:e}=await q(),o=process.argv[3]??e;await C()||await v(),await it(o,"HEAD")||(console.warn("Conflicts would occur. Not safe to rebranch."),process.exit(1));let n=await w(),r=(async()=>{await T(t,o)})();It(Gt(m,{msg:`Updating branch ${o}`,promise:r})),await r;let i=`${Ie(8)}`,a=(async()=>{await s(`git switch ${n}`),await s(`git branch ${i}`),await s(`git switch ${o}`),await s(`git branch -D ${n}`),await s(`git switch -c ${n}`);let c=await F(o,i,!0);for(let l of c)try{await s(`git cherry-pick ${l}`)}catch{let p=Ge.yellow(`git branch -D ${n} && git branch -m ${i} ${n}`);throw new Error(`\u274C cherry pick failed at ${l}
10
+ Run this to restore backup branch
11
+ > ${p}`)}await s(`git branch -D ${i}`)})();It(Gt(m,{msg:`Rewriting branch ${n}`,promise:a})),await a,console.info(`Successfully recreated branch ${n} from ${o}`)}import{execSync as Me}from"node:child_process";async function Ft(){R();let t=Fe(process.argv[3]),{default:e}=await import("clipboardy");await e.write(t),console.log(`'${t}' copied to clipboard`)}function Fe(t="HEAD"){return Me(`git rev-parse --short ${t}`,{encoding:"utf-8"}).trim()}import{render as He}from"ink";import{jsx as Le}from"react/jsx-runtime";async function Ht(){let{remote:t,branch:e}=await X();h(t),await A();let o=G(t,e);He(Le(m,{msg:`Fetching branch ${e} from ${t}`,promise:o})),await o,await f(["switch","-c",e,"--track",`${t}/${e}`])}async function Z(){let{stdout:t}=await s("npm list -g bisgit --depth=0 --json");return JSON.parse(t.trim()).dependencies.bisgit.version}async function Lt(){console.info(await Z())}async function Ne(){let{code:t}=await d("npm",["outdated","-g","bisgit"]);return t===0}async function Ue(){let{stdout:t}=await s("npm view bisgit version",{encoding:"utf8"});return t.trim()}async function Nt(){if(await Ne())return console.info("Already up to date");console.info(`Updating: ${await Z()} -> ${await Ue()}`),b("npm",["i","-g","bisgit@latest"])}async function Ut(){let[t,e]=await Promise.allSettled([await je("user.name"),await Oe()]);t.status==="fulfilled"&&console.info(`Git: ${t.value}`),e.status==="fulfilled"&&console.info(`Github: ${e.value}`)}async function Oe(){let{stdout:t}=await s("gh api user --jq .login");return t.trim()}async function je(t){let{stdout:e}=await s(`git config ${t}`);return e.trim()}import{render as Ze}from"ink";import{Text as _e,useApp as Ve,useInput as Ye}from"ink";import{useState as ze}from"react";import{Fragment as Ke,jsx as Je,jsxs as Ot}from"react/jsx-runtime";function jt({prompt:t,msg:e,onConfirm:o,requireConfirmation:n}){let[r,i]=ze(""),{exit:a}=Ve();return Ye((c,l)=>{if(r)return;let p=c.toLowerCase();p==="y"||l.return&&!n?i("Yes"):(p==="n"||l.return&&n)&&(i("No"),a())}),Ot(Ke,{children:[Ot(_e,{children:[t," [",n?"y/N":"Y/n","] ",r]}),r==="Yes"&&Je(m,{msg:e,promise:o()})]})}import{jsx as Qe}from"react/jsx-runtime";async function _t(){if(at(),await C())return console.log("Already a clean working tree");let t=await M();if(!t)throw new Error("git status cmd failed");let e=new Q(t);e.displayReport(),Ze(Qe(jt,{prompt:"Approve these changes?",msg:"Running git reset && git clean",onConfirm:async()=>(await s("git reset --hard"),await s("git clean -df"),`Altered ${e.willDelete.length+e.willRecreate.length+e.willRevert.length} files and folders.`)}))}var Q=class{willDelete=[];willRecreate=[];willRevert=[];constructor(e){e.forEach(o=>{if(o){o=o.trim();let n=o.indexOf(" ");if(n===-1)throw new Error("error parsing status porcelain");let r=o.slice(0,n).trim(),i=o.slice(n+1);r.includes("?")||r.includes("A")?this.willDelete.push(i):r==="DU"||r==="D"?this.willRecreate.push(i):this.willRevert.push(i)}}),this.willDelete.sort(),this.willRecreate.sort(),this.willRevert.sort()}displayReport(){this.displaySection("Will Recreate:",this.willRecreate),this.displaySection("Will Revert:",this.willRevert),this.displaySection("Will Delete:",this.willDelete)}displaySection(e,o){o.length&&console.log(`${e}
12
+ ${o.map(n=>`- ${n}`).join(`
13
+ `)}`)}};import{nanoid as Xe}from"nanoid";import{render as to}from"ink";import{jsx as eo}from"react/jsx-runtime";async function Vt(){await U();let t=process.argv[3]??"origin";h(t);let e=await w();ct(e);let o="",r=(async()=>{let i=[s(`git fetch ${t} ${e} --force`)];await C()||i.push(v()),await Promise.all(i);let[a,c]=await Promise.all([W(t,e),I(t,e)]);if(!(a===0&&c===0)){if(a!==0){let l=`${e}-${Xe(8)}`;o=`Created branch ${l}`,await s(`git branch ${l}`)}await s(`git reset --hard ${t}/${e}`)}})();to(eo(m,{msg:`Force pull reseting ${e} -> ${t}`,promise:r})),await r,o&&console.info(o)}var Yt={abort:lt,amend:ft,autoprune:wt,backmerge:gt,churn:ht,coauthor:Pt,"code-review":Rt,conflict:At,continue:St,exclude:vt,files:Dt,fixup:Et,include:kt,languages:Bt,lines:Tt,pwd:qt,rebranch:Mt,"remote-default":dt,savepoint:v,sha:Ft,track:Ht,update:Nt,"--version":Lt,whoami:Ut,wipe:_t,yank:Vt};async function vn(t){return await Yt[t]?.(),Object.hasOwn(Yt,t)}export{vn as runCommand};
package/dist/main.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{a as o,d as t}from"./chunks/chunk-HKY7QTE6.js";import"./chunks/chunk-7XT4D6II.js";import"./chunks/chunk-R7DNYVL6.js";async function a(){let r=o();if(!r){t();let{renderApp:i}=await import("./chunks/pages-YLGVYIE5.js");return i()}let{runCommand:n}=await import("./chunks/commands-6NWVWJQB.js");if(await n(r))return;let{runWrapper:e}=await import("./chunks/wrapper-PHXQ7CVF.js");await e(r)||(console.error("unknown command"),process.exit(1))}a().catch(r=>{console.error(`An error occurred: ${r.stderr??r.message}`),process.exit(1)});
2
+ import{a as o,d as t}from"./chunks/chunk-HKY7QTE6.js";import"./chunks/chunk-7XT4D6II.js";import"./chunks/chunk-R7DNYVL6.js";async function a(){let r=o();if(!r){t();let{renderApp:i}=await import("./chunks/pages-YLGVYIE5.js");return i()}let{runCommand:n}=await import("./chunks/commands-YU4ZLADN.js");if(await n(r))return;let{runWrapper:e}=await import("./chunks/wrapper-PHXQ7CVF.js");await e(r)||(console.error("unknown command"),process.exit(1))}a().catch(r=>{console.error(`An error occurred: ${r.stderr??r.message}`),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bisgit",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Git CLI tool to simplify common advanced git workflows",
5
5
  "main": "dist/main.js",
6
6
  "bin": {
@@ -41,10 +41,10 @@
41
41
  "prepare": "husky"
42
42
  },
43
43
  "devDependencies": {
44
- "@types/node": "^25.0.10",
45
- "@types/react": "^19.2.9",
46
- "@typescript-eslint/eslint-plugin": "^8.53.1",
47
- "@typescript-eslint/parser": "^8.53.1",
44
+ "@types/node": "^25.1.0",
45
+ "@types/react": "^19.2.10",
46
+ "@typescript-eslint/eslint-plugin": "^8.54.0",
47
+ "@typescript-eslint/parser": "^8.54.0",
48
48
  "esbuild": "^0.27.2",
49
49
  "esbuild-lazy-analyzer": "^1.4.0",
50
50
  "esbuild-visualizer": "^0.7.0",
@@ -64,7 +64,7 @@
64
64
  "ink-spinner": "^5.0.0",
65
65
  "ink-text-input": "^6.0.0",
66
66
  "nanoid": "^5.1.6",
67
- "react": "^19.2.3",
67
+ "react": "^19.2.4",
68
68
  "strip-json-comments": "^5.0.3"
69
69
  }
70
70
  }
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
- import{b as g,c as X,d as at,e as R,f as w,g as V,h as A,i as N,j as U,k as ct,l as y,m as S}from"./chunk-HKY7QTE6.js";import{a as C,d as h,e as tt,f as W,g as G,h as k,i as et,j as ot,k as rt,m as I,n as x,o as M,p as P,q as it,r as nt,s as F,t as st,w as H,x as L}from"./chunk-7XT4D6II.js";import{a as b,b as s,c as E,d,e as f}from"./chunk-R7DNYVL6.js";import B from"node:path";async function mt(){let t=await M(),e=/^(UU|DU|UD)/;return!!t?.some(o=>e.test(o))}async function j(){let t=await et(),[e,o,r,i,n]=await Promise.all([await C(B.join(t,"MERGE_HEAD")),await C(B.join(t,"rebase-merge")),await C(B.join(t,"rebase-apply")),await C(B.join(t,"CHERRY_PICK_HEAD")),await C(B.join(t,"REVERT_HEAD"))]);return{merge:e,rebaseMerge:o,rebaseApply:r,cherryPick:i,revert:n}}async function lt(){let{merge:t,rebaseMerge:e,rebaseApply:o,cherryPick:r,revert:i}=await j(),n="";if(t)n="merge";else if(e||o)n="rebase";else if(r)n="cherry-pick";else if(i)n="revert";else{let a=await mt()?"Conflicts exist, but likely are from a stash and are not abortable. Resolve them manually.":"Nothing to abort.";console.log(a);return}console.log(`Aborting the ${n}`),await f([n,"--abort"])}async function ft(){await U(),await S(),b("git",["commit","--amend","--no-edit",...g()],{stdio:"inherit",silent:!0,triggerExit:!0})}import{render as re}from"ink";import{render as ee}from"ink";import{Suspense as zt,use as Jt,useEffect as Kt}from"react";import{Text as pt,useApp as Zt}from"ink";import Qt from"ink-spinner";import{jsx as O,jsxs as te}from"react/jsx-runtime";function m(t){let{msg:e}=t;return O(zt,{fallback:te(pt,{children:[O(Qt,{type:"dots"}),"\xA0",e]}),children:O(Xt,{...t})})}function Xt({msg:t,promise:e}){let o=Jt(e),{exit:r}=Zt();return Kt(()=>{r()},[o]),O(pt,{children:`\u2714 ${typeof o=="string"?o:t}`})}import{jsx as oe}from"react/jsx-runtime";async function gt(){let t=process.argv[3],e=process.argv[4]??await h();if(V(t),V(e),t===e)return console.log(`No reason to merge '${t}' into '${e}'`);let o=await tt(t);w(o),ee(oe(m,{msg:"Updating target branch and merging",promise:(async()=>{try{await T(o,t)}catch{console.error(`Error when updating branch ${t} with remote ${o}. Fix divergent branches before merging into ${e}`);return}await h()!==e&&await s(`git switch ${e}`),b("git",["merge",t],{stdio:"inherit",silent:!0})})()}))}async function T(t,e){await I(t,e);let[o,r,i]=await Promise.all([W(t,e),G(t,e),h()]);if(r!==0){if(o===0&&i!==e){await s(`git fetch ${t} ${e}:${e}`);return}if(await s(`git switch ${e}`),o===0){await s(`git merge ${t}/${e}`);return}await f(["merge",`${t}/${e}`],["ignore","ignore","inherit"])}}async function q(){R(),w();let{stdout:t,code:e}=await d("git",["rev-parse","--abbrev-ref","origin/HEAD"]);if(e===0)return ut(t.trim());await s("git remote set-head origin -a");let{stdout:o}=await s("git rev-parse --abbrev-ref origin/HEAD");return ut(o.trim())}async function dt(){let{remote:t,branch:e}=await q();console.log(`Remote default branch is '${t}/${e}'`)}async function ut(t){let e=t.split("/"),o=t.split("/").map((r,i)=>e.slice(0,i+1).join("/"));for(let r of o)if(await rt(r)){let i=t.slice(r.length+1);return{remote:r,branch:i}}throw new Error("Failed to get default remote")}import{jsx as ne}from"react/jsx-runtime";var ie=["master","main","development","lingoport"];async function ht(){await A();let{branch:t,remote:e}=await q();await s(`git switch ${t}`);let o=(async()=>{await f(["fetch","--prune","--prune-tags"]),await T(e,t)})();re(ne(m,{msg:"Fetching and pruning remote references",promise:o})),await o;let r=await st();for(let i of r){if(i===t||ie.includes(i))continue;let{code:n}=await d("git",["diff","--quiet",t,i]);if(n===0){Y(i);continue}let{code:a}=await d("git",["merge-base","--is-ancestor",i,t]);if(a===0){Y(i);continue}let c=await P(i,t),{stdout:l}=await d("git",["merge-tree",c,t,i]);l?.trim()||Y(i)}}function Y(t){f(["branch","-D",t])}import{spawn as se}from"node:child_process";import{createInterface as ae}from"node:readline/promises";async function wt(){R;let e=[...(await ce()).entries()].sort(([,r],[,i])=>i-r).slice(0,25),o=e[0][1].toString().length;console.info(e.map(([r,i])=>`${String(i).padEnd(o)} ${r}:`).join(`
3
- `))}async function ce(){let{promise:t,resolve:e,reject:o}=Promise.withResolvers(),r=new Map,i=se("git",["log","--all","-M","-C","--name-only","--format=format:"]),n=ae({input:i.stdout,crlfDelay:1/0});return n.on("line",a=>{let c=a.trim();c&&r.set(c,(r.get(c)??0)+1)}),n.on("close",()=>e(r)),i.on("error",o),t}import{render as bt}from"ink";import{Box as me,Text as le,useApp as fe,useInput as pe}from"ink";import ge from"ink-select-input";import{jsx as yt,jsxs as ue}from"react/jsx-runtime";function $t({prompt:t,onSelect:e,items:o}){let{exit:r}=fe();return pe((i,n)=>{n.escape&&r()}),ue(me,{flexDirection:"column",children:[yt(le,{children:t}),yt(ge,{items:o,onSelect:e})]})}import{jsx as xt}from"react/jsx-runtime";async function Pt(){await S();let t=g()[0];if(!t){let n=(await he()).map(c=>({value:c,label:`${c.name} ${c.email} (${c.commits})`}));bt(xt($t,{items:n,prompt:"Who assisted in this commit?",onSelect:({value:{name:c,email:l}})=>{Ct(c,l.slice(1,-1))}}));return}let e=(async()=>{let i=await de(t);return i.email||(console.error(`Couldn't find an email for ${t}`),process.exit(1)),i})();bt(xt(m,{msg:"Fetching name and email",promise:e}));let{name:o,email:r}=await e;Ct(o,r)}async function de(t){let{stdout:e}=await s(`gh api users/${t}`);return JSON.parse(e.trim())}async function he(){let t=await E('git log --format="%an|<%ae>"'),e=new Map;for(let o of t){let[r,i]=o.split("|"),n=`${r}|${i}`;e.has(n)||e.set(n,{name:r,email:i,commits:0}),e.get(n).commits+=1}return[...e.values()].toSorted((o,r)=>r.commits-o.commits)}async function Ct(t,e){f(["commit","--edit","-m","<insert summary>","-m",`Co-authored-by: ${t} <${e}>`])}import{render as z}from"ink";import{isDeepStrictEqual as we}from"node:util";import{jsx as J}from"react/jsx-runtime";async function Rt(){let t=y("Error: missing id of PR to checkout");await A();let e=(async()=>Promise.all([s(`gh co ${t}`),s(`gh pr view ${t} --json baseRefName -q .baseRefName`)]))();z(J(m,{msg:`Checking out pr #${t}`,promise:e}));let[,{stdout:o}]=await e,r=o.trim(),i=(async()=>{await s(`git switch ${r}`),await s("git pull"),await s("git switch -")})();z(J(m,{msg:`Updating ${r} branch merge destination`,promise:i})),await i;let n=(async()=>{let p=await P(r,"HEAD");return await s(`git reset ${p} --soft`),await ye("HEAD")})();z(J(m,{msg:"Creating an editable, explorable, local PR experience",promise:n}));let[a,c]=await Promise.all([n,$e(t)]),{files:l,additions:u,deletions:D}=c;if(we(a,c))return console.info(`Files: ${l}, +${u} -${D}`);console.info("The PR stat doesn't match the local stat."),console.info("LOCAL"),console.table(a),console.info("GITHUB"),console.table(c),console.info("One option to fix (there'll likely be conflicts):"),console.info("1. git stash -u"),console.info(`2. git merge ${r}`),console.info("3. git stash pop")}async function ye(t){let{stdout:e}=await s(`git diff --shortstat ${t}`),o=/(\d+)\s+files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/,r=e.trim().match(o);if(!r)throw new Error(`Couldn't generate short stat for ref(s): ${t}`);let[,i,n,a]=r;return{files:parseInt(i,10),additions:n?parseInt(n,10):0,deletions:a?parseInt(a,10):0}}async function $e(t){let{stdout:e}=await s(`gh pr view ${t} --json deletions,files,additions`),o=JSON.parse(e.trim());return o.files=o.files.length,o}import{spawn as be}from"node:child_process";import{createInterface as Ce}from"node:readline/promises";import K from"chalk";async function At(){let t=y("Error: missing target branch argument"),e=await P("HEAD",t),{promise:o,resolve:r,reject:i}=Promise.withResolvers(),n=be("git",["merge-tree",e,"HEAD",t]),a=Ce({input:n.stdout,crlfDelay:1/0}),c=!1,l=0;a.on("line",p=>{p=p.trimEnd(),p==="+<<<<<<< .our"?(c=!0,console.info(K.red(p)),l+=1):p==="+>>>>>>> .their"?(c=!1,console.info(K.green(p))):p==="+======="?console.info(K.yellow(p)):c&&console.info(p)}),a.on("close",()=>r(l)),n.on("error",i);let u=await o,D=u?`\u274C ${u} conflicts would occur!`:"\u2705 No conflicts. Safe to merge.";console.info(D)}async function St(){let{merge:t,rebaseMerge:e,rebaseApply:o,cherryPick:r,revert:i}=await j(),n="";if(t)n="merge";else if(e||o)n="rebase";else if(r)n="cherry-pick";else if(i)n="revert";else{console.log("Nothing to continue.");return}console.log(`Continuing the ${n}`),await f([n,"--continue"])}import{appendFileSync as Pe}from"node:fs";import{readFile as xe}from"node:fs/promises";async function _(t){return(await xe(t,"utf-8")).split(/\r?\n/).map(o=>o.trim()).filter(o=>o&&!o.startsWith("#"))}async function vt(){let t=await k("info/exclude");await N(t);let e=await _(t);g().forEach(o=>{e.includes(o)?console.info(`Already Exists: '${o}'`):(Pe(t,`${o}
4
- `),console.info(`Added '${o}'`))}),console.info(`
5
- See file at ${t}`)}async function Dt(){let t=g();if(t[0]){let e=await Re(t[0]);console.info(e.join(`
6
- `))}else f(["status","--short"])}async function Re(t){return L(t)?await E(`git stash show -p --include-untracked --name-only ${t}`):await E(`git show --name-only --pretty=format:"" ${t}`)}import{spawn as Ae}from"node:child_process";async function Et(){let t=y("Error: missing valid target ref argument");await S();let e=await nt(t);await f(["commit",`--fixup=${e}`]);let r=(await F(`${e}^`,"HEAD",!0)).map(n=>Se(n));(await Promise.all(r)).every(Boolean)||(console.warn("Rebase conflict would occur!"),await s("git reset HEAD~1 --soft"),process.exit(1)),await s(`git rebase -i --autosquash ${e}^`)}async function Se(t){let{stdout:e}=await s(`git diff ${t}^ ${t}`),{promise:o,resolve:r,reject:i}=Promise.withResolvers(),n=Ae("git",["apply","--check","--3way","-q"],{stdio:["pipe","ignore","ignore"]});return n.on("close",a=>{r(a===0)}),n.on("error",i),n.stdin.write(e),n.stdin.end(),o}import{readFile as ve,writeFile as De}from"node:fs/promises";async function kt(){let t=await k("info/exclude");await N(t);let e=await _(t),o=g();o.filter(a=>!e.includes(a)).forEach(a=>console.info(`No match: '${a}'`));let i=(await ve(t,"utf-8")).split(/\r?\n/).map(a=>a.trim()),n=i.filter(a=>!o.includes(a));await De(t,n.join(`
7
- `)),console.info(`
8
- Removed ${i.length-n.length} entries from ${t}`)}import{render as Ee}from"ink";import{jsx as qe}from"react/jsx-runtime";async function Bt(){let t=(async()=>{let i=await ke();return await Be(i)})();Ee(qe(m,{msg:"Fetching repo languages",promise:t}));let e=await t,o=Object.values(e).reduce((i,n)=>i+n,0),r=Object.entries(e).map(([i,n])=>`${i}: ${Math.round(n/o*100)}% - ${Te(n)}`);console.log(r.join(`
9
- `))}async function ke(){let{stdout:t}=await s("gh repo view --json nameWithOwner -q .nameWithOwner");return t.trim()}async function Be(t){let{stdout:e}=await s(`gh api repos/${t}/languages`);return JSON.parse(e.trim())}function Te(t,e=2){if(t===0)return"0 B";let o=1024,r=e<0?0:e,i=["B","KB","MB","GB","TB","PB","EB","ZB","YB"],n=Math.floor(Math.log(t)/Math.log(o));return`${parseFloat((t/Math.pow(o,n)).toFixed(r))} ${i[n]}`}import $ from"chalk";async function Tt(){y();let t=g(),[e,o]=t.filter(i=>i!=="-v"),r=[];if(L(e)?(r.push(...await H(`${e}^3`)),r.push(...await H(`${e}^2`))):r.push(...await H(e,o)),t.includes("-v")){let i={added:"A",modified:"M",deleted:"D",binary:"B"};r.forEach(n=>{let c=`${We(n.changeType)(i[n.changeType])} ${n.file} |`;n.added&&(c+=$.green(` +${n.added}`)),n.deleted&&(c+=$.red(` -${n.deleted}`)),console.info(c)})}else{let i=new Set(r.map(({file:u})=>u)).size,[n,a]=r.reduce((u,{added:D,deleted:p})=>[u[0]+(D??0),u[1]+(p??0)],[0,0]),c=$.green(`+${n}`),l=$.red(`-${a}`);console.info(`${i} files: ${c} ${l}`)}}var We=t=>{switch(t){case"modified":return $.yellow;case"added":return $.green;case"deleted":return $.red;default:return e=>e}};async function qt(){let t=await ot();console.log(t)}import{render as Gt}from"ink";function Wt(){return new Date().toLocaleString("en-US",{year:"2-digit",month:"2-digit",day:"2-digit",hour:"numeric",minute:"2-digit",hour12:!0}).replace(",","")}async function v(){let t=Wt();await s("git add -A"),await f(["commit","-m",`"WIP ${t}"`])}import{nanoid as Ge}from"nanoid";import Ie from"chalk";import{jsx as It}from"react/jsx-runtime";async function Mt(){let{remote:t,branch:e}=await q(),o=process.argv[3]??e;await x()||await v(),await it(o,"HEAD")||(console.warn("Conflicts would occur. Not safe to rebranch."),process.exit(1));let r=await h(),i=(async()=>{await T(t,o)})();Gt(It(m,{msg:`Updating branch ${o}`,promise:i})),await i;let n=`${Ge(8)}`,a=(async()=>{await s(`git switch ${r}`),await s(`git branch ${n}`),await s(`git switch ${o}`),await s(`git branch -D ${r}`),await s(`git switch -c ${r}`);let c=await F(o,n,!0);for(let l of c)try{await s(`git cherry-pick ${l}`)}catch{let u=Ie.yellow(`git branch -D ${r} && git branch -m ${n} ${r}`);throw new Error(`\u274C cherry pick failed at ${l}
10
- Run this to restore backup branch
11
- > ${u}`)}await s(`git branch -D ${n}`)})();Gt(It(m,{msg:`Rewriting branch ${r}`,promise:a})),await a,console.info(`Successfully recreated branch ${r} from ${o}`)}import{execSync as Me}from"node:child_process";async function Ft(){R();let t=Fe(process.argv[3]),{default:e}=await import("clipboardy");await e.write(t),console.log(`'${t}' copied to clipboard`)}function Fe(t="HEAD"){return Me(`git rev-parse --short ${t}`,{encoding:"utf-8"}).trim()}import{render as He}from"ink";import{jsx as Le}from"react/jsx-runtime";async function Ht(){let{remote:t,branch:e}=await X();w(t),await A();let o=I(t,e);He(Le(m,{msg:`Fetching branch ${e} from ${t}`,promise:o})),await o,await f(["switch","-c",e,"--track",`${t}/${e}`])}async function Z(){let{stdout:t}=await s("npm list -g bisgit --depth=0 --json");return JSON.parse(t.trim()).dependencies.bisgit.version}async function Lt(){console.info(await Z())}async function Ne(){let{code:t}=await d("npm",["outdated","-g","bisgit"]);return t===0}async function Ue(){let{stdout:t}=await s("npm view bisgit version",{encoding:"utf8"});return t.trim()}async function Nt(){if(await Ne())return console.info("Already up to date");console.info(`Updating: ${await Z()} -> ${await Ue()}`),b("npm",["i","-g","bisgit@latest"])}async function Ut(){let[t,e]=await Promise.allSettled([await Oe("user.name"),await je()]);t.status==="fulfilled"&&console.info(`Git: ${t.value}`),e.status==="fulfilled"&&console.info(`Github: ${e.value}`)}async function je(){let{stdout:t}=await s("gh api user --jq .login");return t.trim()}async function Oe(t){let{stdout:e}=await s(`git config ${t}`);return e.trim()}import{render as Ze}from"ink";import{Text as _e,useApp as Ve,useInput as Ye}from"ink";import{useState as ze}from"react";import{Fragment as Ke,jsx as Je,jsxs as jt}from"react/jsx-runtime";function Ot({prompt:t,msg:e,onConfirm:o}){let[r,i]=ze(""),{exit:n}=Ve();return Ye((a,c)=>{if(r)return;let l=a.toLowerCase();l==="y"?i("Yes"):(l==="n"||c.return)&&(i("No"),n())}),jt(Ke,{children:[jt(_e,{children:[t," [y/N] ",r]}),r==="Yes"&&Je(m,{msg:e,promise:o()})]})}import{jsx as Qe}from"react/jsx-runtime";async function _t(){if(at(),await x())return console.log("Already a clean working tree");let t=await M();if(!t)throw new Error("git status cmd failed");let e=new Q(t);e.displayReport(),Ze(Qe(Ot,{prompt:"Approve these changes?",msg:"Running git reset && git clean",onConfirm:async()=>(await s("git reset --hard"),await s("git clean -f"),`Altered ${e.willDelete.length+e.willRecreate.length+e.willRevert.length} files.`)}))}var Q=class{willDelete=[];willRecreate=[];willRevert=[];constructor(e){e.forEach(o=>{if(o){let r=o.slice(0,2).trim(),i=o.slice(3);r.includes("?")||r.includes("A")?this.willDelete.push(i):r==="DU"||r==="D"?this.willRecreate.push(i):this.willRevert.push(i)}}),this.willDelete.sort(),this.willRecreate.sort(),this.willRevert.sort()}displayReport(){this.displaySection("Will Recreate:",this.willRecreate),this.displaySection("Will Revert:",this.willRevert),this.displaySection("Will Delete:",this.willDelete)}displaySection(e,o){o.length&&console.log(`${e}
12
- ${o.map(r=>`- ${r}`).join(`
13
- `)}`)}};import{nanoid as Xe}from"nanoid";import{render as to}from"ink";import{jsx as eo}from"react/jsx-runtime";async function Vt(){await U();let t=process.argv[3]??"origin";w(t);let e=await h();ct(e);let o="",i=(async()=>{let n=[s(`git fetch ${t} ${e} --force`)];await x()||n.push(v()),await Promise.all(n);let[a,c]=await Promise.all([W(t,e),G(t,e)]);if(!(a===0&&c===0)){if(a!==0){let l=`${e}-${Xe(8)}`;o=`Created branch ${l}`,await s(`git branch ${l}`)}await s(`git reset --hard ${t}/${e}`)}})();to(eo(m,{msg:`Force pull reseting ${e} -> ${t}`,promise:i})),await i,o&&console.info(o)}var Yt={abort:lt,amend:ft,autoprune:ht,backmerge:gt,churn:wt,coauthor:Pt,"code-review":Rt,conflict:At,continue:St,exclude:vt,files:Dt,fixup:Et,include:kt,languages:Bt,lines:Tt,pwd:qt,rebranch:Mt,"remote-default":dt,savepoint:v,sha:Ft,track:Ht,update:Nt,"--version":Lt,whoami:Ut,wipe:_t,yank:Vt};async function vn(t){return await Yt[t]?.(),Object.hasOwn(Yt,t)}export{vn as runCommand};