diffstalker 0.1.7 → 0.2.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/.github/workflows/release.yml +8 -0
- package/CHANGELOG.md +36 -0
- package/bun.lock +89 -306
- package/dist/App.js +895 -520
- package/dist/FollowMode.js +85 -0
- package/dist/KeyBindings.js +178 -0
- package/dist/MouseHandlers.js +156 -0
- package/dist/core/ExplorerStateManager.js +632 -0
- package/dist/core/FilePathWatcher.js +133 -0
- package/dist/core/GitStateManager.js +221 -86
- package/dist/git/diff.js +4 -0
- package/dist/git/ignoreUtils.js +30 -0
- package/dist/git/status.js +2 -34
- package/dist/index.js +68 -53
- package/dist/ipc/CommandClient.js +165 -0
- package/dist/ipc/CommandServer.js +152 -0
- package/dist/state/CommitFlowState.js +86 -0
- package/dist/state/UIState.js +195 -0
- package/dist/types/tabs.js +4 -0
- package/dist/ui/Layout.js +252 -0
- package/dist/ui/PaneRenderers.js +56 -0
- package/dist/ui/modals/BaseBranchPicker.js +110 -0
- package/dist/ui/modals/DiscardConfirm.js +77 -0
- package/dist/ui/modals/FileFinder.js +232 -0
- package/dist/ui/modals/HotkeysModal.js +209 -0
- package/dist/ui/modals/ThemePicker.js +107 -0
- package/dist/ui/widgets/CommitPanel.js +58 -0
- package/dist/ui/widgets/CompareListView.js +238 -0
- package/dist/ui/widgets/DiffView.js +281 -0
- package/dist/ui/widgets/ExplorerContent.js +89 -0
- package/dist/ui/widgets/ExplorerView.js +204 -0
- package/dist/ui/widgets/FileList.js +185 -0
- package/dist/ui/widgets/Footer.js +50 -0
- package/dist/ui/widgets/Header.js +68 -0
- package/dist/ui/widgets/HistoryView.js +69 -0
- package/dist/utils/displayRows.js +185 -6
- package/dist/utils/explorerDisplayRows.js +1 -1
- package/dist/utils/fileCategories.js +37 -0
- package/dist/utils/fileTree.js +148 -0
- package/dist/utils/languageDetection.js +56 -0
- package/dist/utils/pathUtils.js +27 -0
- package/dist/utils/wordDiff.js +50 -0
- package/eslint.metrics.js +16 -0
- package/metrics/.gitkeep +0 -0
- package/metrics/v0.2.1.json +268 -0
- package/package.json +14 -12
- package/dist/components/BaseBranchPicker.js +0 -60
- package/dist/components/BottomPane.js +0 -101
- package/dist/components/CommitPanel.js +0 -58
- package/dist/components/CompareListView.js +0 -110
- package/dist/components/ExplorerContentView.js +0 -80
- package/dist/components/ExplorerView.js +0 -37
- package/dist/components/FileList.js +0 -131
- package/dist/components/Footer.js +0 -6
- package/dist/components/Header.js +0 -107
- package/dist/components/HistoryView.js +0 -21
- package/dist/components/HotkeysModal.js +0 -108
- package/dist/components/Modal.js +0 -19
- package/dist/components/ScrollableList.js +0 -125
- package/dist/components/ThemePicker.js +0 -42
- package/dist/components/TopPane.js +0 -14
- package/dist/components/UnifiedDiffView.js +0 -115
- package/dist/hooks/useCommitFlow.js +0 -66
- package/dist/hooks/useCompareState.js +0 -123
- package/dist/hooks/useExplorerState.js +0 -248
- package/dist/hooks/useGit.js +0 -156
- package/dist/hooks/useHistoryState.js +0 -62
- package/dist/hooks/useKeymap.js +0 -167
- package/dist/hooks/useLayout.js +0 -154
- package/dist/hooks/useMouse.js +0 -87
- package/dist/hooks/useTerminalSize.js +0 -20
- package/dist/hooks/useWatcher.js +0 -137
- package/dist/utils/mouseCoordinates.js +0 -165
- package/dist/utils/rowCalculations.js +0 -209
package/dist/index.js
CHANGED
|
@@ -1,45 +1,60 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
`)}function
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
`),lines:Y}}function aY(X,Y){if(!X||Y<0||Y>=X.files.length)return 0;let $=T$(X),J=0,Z=0;for(let K of $.lines){if(K.type==="header"&&K.content.startsWith("diff --git")){if(Z===Y)return J;Z++}if(!w8(K))continue;J++}return 0}function lX(X,Y,$,J=!0,Z=!0){let K=0;if(Y>0){if(X===K)return-1;if(K++,J){if(X<K+Y)return X-K;K+=Y}}if($>0){if(Y>0){if(X===K)return-1;K++}if(X===K)return-1;if(K++,Z){if(X<K+$)return Y+(X-K)}}return-1}function tY({commits:X,selectedIndex:Y,scrollOffset:$,maxHeight:J,isActive:Z,width:K,onSelectCommit:Q}){if(X.length===0)return j0(C$,{children:j0(p0,{dimColor:!0,children:"No commits yet"})});return j0(x0,{items:X,maxHeight:J,scrollOffset:$,getKey:(V)=>V.hash,renderItem:(V,G)=>{let q=G===Y&&Z,z=ZX(V.date),N=11+z.length+2,A=K-N,{displayMessage:E,displayRefs:U}=KX(V.message,V.refs,A);return nX(iY,{children:[j0(p0,{color:"yellow",children:V.shortHash}),j0(p0,{children:" "}),j0(p0,{color:q?"cyan":void 0,bold:q,inverse:q,children:E}),j0(p0,{children:" "}),nX(p0,{dimColor:!0,children:["(",z,")"]}),U&&nX(iY,{children:[j0(p0,{children:" "}),j0(p0,{color:"green",children:U})]})]})}})}import{jsx as y0,Fragment as S$,jsxs as qX}from"react/jsx-runtime";import{Box as b$,Text as E0}from"ink";function eY({activeTab:X,mouseEnabled:Y=!0,autoTabEnabled:$=!1,wrapMode:J=!1,showMiddleDots:Z=!1}){return qX(b$,{justifyContent:"space-between",children:[qX(E0,{children:[y0(E0,{dimColor:!0,children:"?"})," ",y0(E0,{color:"yellow",children:Y?"[scroll]":"m:[select]"})," ",y0(E0,{color:$?"blue":void 0,dimColor:!$,children:"[auto]"})," ",y0(E0,{color:J?"blue":void 0,dimColor:!J,children:"[wrap]"}),X==="explorer"&&qX(S$,{children:[" ",y0(E0,{color:Z?"blue":void 0,dimColor:!Z,children:"[dots]"})]})]}),qX(E0,{children:[y0(E0,{color:X==="diff"?"cyan":void 0,bold:X==="diff",children:"[1]Diff"})," ",y0(E0,{color:X==="commit"?"cyan":void 0,bold:X==="commit",children:"[2]Commit"})," ",y0(E0,{color:X==="history"?"cyan":void 0,bold:X==="history",children:"[3]History"})," ",y0(E0,{color:X==="compare"?"cyan":void 0,bold:X==="compare",children:"[4]Compare"})]})]})}import{jsx as o,jsxs as e,Fragment as p8}from"react/jsx-runtime";import h$ from"react";import{Box as t0,Text as s}from"ink";import{jsx as n,jsxs as M0,Fragment as w$}from"react/jsx-runtime";import{useMemo as g$}from"react";import{Box as x8,Text as h}from"ink";function x$({commit:X,isSelected:Y,isActive:$,width:J}){let Z=ZX(X.date),K=13+Z.length+2,Q=J-K,{displayMessage:V,displayRefs:G}=KX(X.message,X.refs,Q);return M0(x8,{children:[n(h,{children:" "}),n(h,{color:"yellow",children:X.shortHash}),n(h,{children:" "}),n(h,{color:Y&&$?"cyan":void 0,bold:Y&&$,inverse:Y&&$,children:V}),n(h,{children:" "}),M0(h,{dimColor:!0,children:["(",Z,")"]}),G&&M0(w$,{children:[n(h,{children:" "}),n(h,{color:"green",children:G})]})]})}function p$({file:X,isSelected:Y,isActive:$,maxPathLength:J}){let Z={added:"green",modified:"yellow",deleted:"red",renamed:"blue"},K={added:"A",modified:"M",deleted:"D",renamed:"R"},Q=X.isUncommitted??!1,V=5+String(X.additions).length+String(X.deletions).length,G=Q?14:0,q=J-V-G;return M0(x8,{children:[n(h,{children:" "}),Q&&n(h,{color:"magenta",bold:!0,children:"*"}),n(h,{color:Q?"magenta":Z[X.status],bold:!0,children:K[X.status]}),M0(h,{bold:Y&&$,color:Y&&$?"cyan":Q?"magenta":void 0,inverse:Y&&$,children:[" ",v0(X.path,q)]}),n(h,{dimColor:!0,children:" ("}),M0(h,{color:"green",children:["+",X.additions]}),n(h,{dimColor:!0,children:" "}),M0(h,{color:"red",children:["-",X.deletions]}),n(h,{dimColor:!0,children:")"}),Q&&M0(h,{color:"magenta",dimColor:!0,children:[" ","[uncommitted]"]})]})}function X4({commits:X,files:Y,selectedItem:$,scrollOffset:J,maxHeight:Z,isActive:K,width:Q}){let z=g$(()=>{let N=[];if(X.length>0)N.push({type:"section-header",sectionType:"commits"}),X.forEach((A,E)=>{N.push({type:"commit",commitIndex:E,commit:A})});if(Y.length>0){if(X.length>0)N.push({type:"spacer"});N.push({type:"section-header",sectionType:"files"}),Y.forEach((A,E)=>{N.push({type:"file",fileIndex:E,file:A})})}return N},[X,Y,!0,!0]).slice(J,J+Z);if(X.length===0&&Y.length===0)return n(x8,{flexDirection:"column",children:n(h,{dimColor:!0,children:"No changes compared to base branch"})});return n(x8,{flexDirection:"column",children:z.map((N,A)=>{let E=`row-${J+A}`;if(N.type==="section-header"){let U=N.sectionType==="commits",M=U?!0:!0,O=U?X.length:Y.length;return M0(x8,{children:[M0(h,{bold:!0,color:"cyan",children:[M?"▼":"▶"," ",U?"Commits":"Files"]}),M0(h,{dimColor:!0,children:[" (",O,")"]})]},E)}if(N.type==="spacer")return n(h,{children:" "},E);if(N.type==="commit"&&N.commit!==void 0&&N.commitIndex!==void 0){let U=$?.type==="commit"&&$.index===N.commitIndex;return n(x$,{commit:N.commit,isSelected:U,isActive:K,width:Q},E)}if(N.type==="file"&&N.file!==void 0&&N.fileIndex!==void 0){let U=$?.type==="file"&&$.index===N.fileIndex;return n(p$,{file:N.file,isSelected:U,isActive:K,maxPathLength:Q-5},E)}return null})})}import{jsxs as u$,jsx as F0}from"react/jsx-runtime";import{Box as zX,Text as M8}from"ink";function Y4({currentPath:X,items:Y,selectedIndex:$,scrollOffset:J,maxHeight:Z,isActive:K,width:Q,isLoading:V=!1,error:G=null}){if(G)return F0(zX,{flexDirection:"column",children:u$(M8,{color:"red",children:["Error: ",G]})});if(V)return F0(zX,{flexDirection:"column",children:F0(M8,{dimColor:!0,children:"Loading..."})});if(Y.length===0)return F0(zX,{flexDirection:"column",children:F0(M8,{dimColor:!0,children:"(empty directory)"})});let q=Math.min(Math.max(...Y.map((z)=>z.name.length+(z.isDirectory?1:0))),Q-10);return F0(x0,{items:Y,maxHeight:Z,scrollOffset:J,getKey:(z)=>z.path||z.name,renderItem:(z,N)=>{let A=N===$&&K,U=(z.isDirectory?`${z.name}/`:z.name).padEnd(q+1);return F0(zX,{children:F0(M8,{color:A?"cyan":void 0,bold:A,inverse:A,children:z.isDirectory?F0(M8,{color:A?"cyan":"blue",children:U}):F0(M8,{color:A?"cyan":void 0,children:U})})})}})}function $4(X){if(!X)return[];return X.split("/").filter(Boolean)}function J4({bottomTab:X,currentPane:Y,terminalWidth:$,topPaneHeight:J,files:Z,selectedIndex:K,fileListScrollOffset:Q,stagedCount:V,onStage:G,onUnstage:q,commits:z,historySelectedIndex:N,historyScrollOffset:A,onSelectHistoryCommit:E,compareDiff:U,compareListSelection:M,compareScrollOffset:O,includeUncommitted:F,explorerCurrentPath:k="",explorerItems:H=[],explorerSelectedIndex:B=0,explorerScrollOffset:L=0,explorerIsLoading:R=!1,explorerError:S=null,hideHiddenFiles:P=!0,hideGitignored:W=!0}){let{modified:C,untracked:b}=g0(Z),w=C.length,g=b.length;return e(t0,{flexDirection:"column",height:J,width:$,overflowX:"hidden",overflowY:"hidden",children:[(X==="diff"||X==="commit")&&e(p8,{children:[e(t0,{children:[o(s,{bold:!0,color:Y==="files"?"cyan":void 0,children:"STAGING AREA"}),e(s,{dimColor:!0,children:[" ","(",w," modified, ",g," untracked, ",V," staged)"]})]}),o(rY,{files:Z,selectedIndex:K,isFocused:Y==="files",scrollOffset:Q,maxHeight:J-1,width:$,onStage:G,onUnstage:q})]}),X==="history"&&e(p8,{children:[e(t0,{children:[o(s,{bold:!0,color:Y==="history"?"cyan":void 0,children:"COMMITS"}),e(s,{dimColor:!0,children:[" (",z.length," commits)"]})]}),o(tY,{commits:z,selectedIndex:N,scrollOffset:A,maxHeight:J-1,isActive:Y==="history",width:$,onSelectCommit:E})]}),X==="compare"&&e(p8,{children:[e(t0,{children:[o(s,{bold:!0,color:Y==="compare"?"cyan":void 0,children:"COMPARE"}),o(s,{dimColor:!0,children:" (vs "}),o(s,{color:"cyan",children:U?.baseBranch??"..."}),e(s,{dimColor:!0,children:[": ",U?.commits.length??0," commits, ",U?.files.length??0," files) (b)"]}),U&&U.uncommittedCount>0&&e(p8,{children:[o(s,{dimColor:!0,children:" | "}),e(s,{color:F?"magenta":"yellow",children:["[",F?"x":" ","] uncommitted"]}),o(s,{dimColor:!0,children:" (u)"})]})]}),o(X4,{commits:U?.commits??[],files:U?.files??[],selectedItem:M,scrollOffset:O,maxHeight:J-1,isActive:Y==="compare",width:$})]}),X==="explorer"&&e(p8,{children:[e(t0,{justifyContent:"space-between",width:$,children:[e(t0,{children:[o(s,{bold:!0,color:Y==="explorer"?"cyan":void 0,children:"EXPLORER"}),o(s,{dimColor:!0,children:" "}),$4(k).map((p,f,_)=>e(h$.Fragment,{children:[o(s,{color:"blue",children:p}),f<_.length-1&&o(s,{dimColor:!0,children:" / "})]},f)),k&&o(s,{dimColor:!0,children:" /"}),!k&&o(s,{dimColor:!0,children:"(root)"})]}),o(t0,{children:(P||W)&&e(s,{dimColor:!0,children:[P&&"H",W&&"G"]})})]}),o(Y4,{currentPath:k,items:H,selectedIndex:B,scrollOffset:L,maxHeight:J-1,isActive:Y==="explorer",width:$,isLoading:R,error:S})]})]})}import{jsx as U0,jsxs as Y8}from"react/jsx-runtime";import{useMemo as R4}from"react";import{Box as I8,Text as O0}from"ink";import{jsxs as O8,jsx as c}from"react/jsx-runtime";import{useMemo as K4}from"react";import{Box as k8,Text as a}from"ink";var m$={name:"dark",displayName:"Dark",colors:{addBg:"#022800",delBg:"#3D0100",addHighlight:"#044700",delHighlight:"#5C0200",text:"white",addLineNum:"#368F35",delLineNum:"#A14040",contextLineNum:"gray",addSymbol:"greenBright",delSymbol:"redBright"}},f$={name:"light",displayName:"Light",colors:{addBg:"#69db7c",delBg:"#ffa8b4",addHighlight:"#2f9d44",delHighlight:"#d1454b",text:"black",addLineNum:"#2f9d44",delLineNum:"#d1454b",contextLineNum:"#6c757d",addSymbol:"green",delSymbol:"red"}},d$={name:"dark-colorblind",displayName:"Dark (colorblind)",colors:{addBg:"#004466",delBg:"#660000",addHighlight:"#0077b3",delHighlight:"#b30000",text:"white",addLineNum:"#0077b3",delLineNum:"#b30000",contextLineNum:"gray",addSymbol:"cyanBright",delSymbol:"redBright"}},c$={name:"light-colorblind",displayName:"Light (colorblind)",colors:{addBg:"#99ccff",delBg:"#ffcccc",addHighlight:"#3366cc",delHighlight:"#993333",text:"black",addLineNum:"#3366cc",delLineNum:"#993333",contextLineNum:"#6c757d",addSymbol:"blue",delSymbol:"red"}},l$={name:"dark-ansi",displayName:"Dark (ANSI)",colors:{addBg:"green",delBg:"red",addHighlight:"greenBright",delHighlight:"redBright",text:"white",addLineNum:"greenBright",delLineNum:"redBright",contextLineNum:"gray",addSymbol:"greenBright",delSymbol:"redBright"}},n$={name:"light-ansi",displayName:"Light (ANSI)",colors:{addBg:"green",delBg:"red",addHighlight:"greenBright",delHighlight:"redBright",text:"black",addLineNum:"green",delLineNum:"red",contextLineNum:"gray",addSymbol:"green",delSymbol:"red"}},VX={dark:m$,light:f$,"dark-colorblind":d$,"light-colorblind":c$,"dark-ansi":l$,"light-ansi":n$},e0=["dark","light","dark-colorblind","light-colorblind","dark-ansi","light-ansi"];function UX(X){return VX[X]??VX.dark}function rX(X){if(X.type==="addition"||X.type==="deletion")return X.content.slice(1);if(X.type==="context")return X.content.startsWith(" ")?X.content.slice(1):X.content;return X.content}function r$(X){switch(X.type){case"header":return{type:"diff-header",content:X.content};case"hunk":return{type:"diff-hunk",content:X.content};case"addition":return{type:"diff-add",lineNum:X.newLineNum,content:rX(X)};case"deletion":return{type:"diff-del",lineNum:X.oldLineNum,content:rX(X)};case"context":return{type:"diff-context",lineNum:X.oldLineNum??X.newLineNum,content:rX(X)}}}function X8(X){if(!X)return[];return X.lines.filter(w8).map(r$)}function GX(X,Y){let $=[];if(X){$.push({type:"commit-header",content:`commit ${X.hash}`}),$.push({type:"commit-header",content:`Author: ${X.author}`}),$.push({type:"commit-header",content:`Date: ${dX(X.date)}`}),$.push({type:"spacer"});for(let J of X.message.split(`
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
`);
|
|
12
|
-
`)
|
|
13
|
-
`),
|
|
14
|
-
`),
|
|
15
|
-
`),
|
|
16
|
-
`)
|
|
17
|
-
`),
|
|
18
|
-
`),
|
|
19
|
-
`),
|
|
20
|
-
`);
|
|
21
|
-
`)
|
|
22
|
-
`).
|
|
23
|
-
`)
|
|
24
|
-
`)
|
|
25
|
-
`)
|
|
26
|
-
`)
|
|
27
|
-
`),
|
|
28
|
-
`)
|
|
29
|
-
`).
|
|
30
|
-
`).filter((
|
|
31
|
-
|
|
32
|
-
`).filter((L)=>L)){let L=B.split("\t");if(L.length>=3){let R=L[0]==="-"?0:parseInt(L[0],10),S=L[1]==="-"?0:parseInt(L[1],10),P=L.slice(2).join("\t");G.set(P,{additions:R,deletions:S,staged:!0,unstaged:!1})}}for(let B of K.trim().split(`
|
|
33
|
-
`).filter((L)=>L)){let L=B.split("\t");if(L.length>=3){let R=L[0]==="-"?0:parseInt(L[0],10),S=L[1]==="-"?0:parseInt(L[1],10),P=L.slice(2).join("\t"),W=G.get(P);if(W)W.additions+=R,W.deletions+=S,W.unstaged=!0;else G.set(P,{additions:R,deletions:S,staged:!1,unstaged:!0})}}let q=await $.status(),z=new Map;for(let B of q.files)if(B.index==="A"||B.working_dir==="?")z.set(B.path,"added");else if(B.index==="D"||B.working_dir==="D")z.set(B.path,"deleted");else if(B.index==="R")z.set(B.path,"renamed");else z.set(B.path,"modified");let N=[],E=(Q+V).split(/(?=^diff --git )/m).filter((B)=>B.trim()),U=new Set;for(let B of E){let L=B.match(/^diff --git a\/.+ b\/(.+)$/m);if(!L)continue;let R=L[1];if(U.has(R))continue;U.add(R);let S=AX(B),P=G.get(R)||{additions:0,deletions:0},W=z.get(R)||"modified";N.push({path:R,status:W,additions:P.additions,deletions:P.deletions,diff:{raw:B,lines:S},isUncommitted:!0})}let M=new Set(J.files.map((B)=>B.path)),O=[];for(let B of J.files){let L=N.find((R)=>R.path===B.path);if(L)O.push(B),O.push(L);else O.push(B)}for(let B of N)if(!M.has(B.path))O.push(B);let F=0,k=0,H=new Set;for(let B of O){if(!H.has(B.path))H.add(B.path);F+=B.additions,k+=B.deletions}return{baseBranch:J.baseBranch,stats:{filesChanged:H.size,additions:F,deletions:k},files:O,commits:J.commits,uncommittedCount:J.uncommittedCount}}import*as S0 from"node:fs";import*as J8 from"node:path";import*as a4 from"node:os";var BX=J8.join(a4.homedir(),".cache","diffstalker","base-branches.json");function qJ(){let X=J8.dirname(BX);if(!S0.existsSync(X))S0.mkdirSync(X,{recursive:!0})}function i4(){try{if(S0.existsSync(BX))return JSON.parse(S0.readFileSync(BX,"utf-8"))}catch{}return{}}function zJ(X){qJ(),S0.writeFileSync(BX,JSON.stringify(X,null,2)+`
|
|
34
|
-
`)}function t4(X){let Y=i4(),$=J8.resolve(X);return Y[$]}function e4(X,Y){let $=i4(),J=J8.resolve(X);$[J]=Y,zJ($)}class $9 extends VJ{repoPath;queue;gitWatcher=null;workingDirWatcher=null;_state={status:null,diff:null,stagedDiff:"",selectedFile:null,isLoading:!1,error:null};_compareState={compareDiff:null,compareBaseBranch:null,compareLoading:!1,compareError:null};_historyState={selectedCommit:null,commitDiff:null};_compareSelectionState={type:null,index:0,diff:null};constructor(X){super();this.repoPath=X,this.queue=S4(X)}get state(){return this._state}get compareState(){return this._compareState}get historyState(){return this._historyState}get compareSelectionState(){return this._compareSelectionState}updateState(X){this._state={...this._state,...X},this.emit("state-change",this._state)}updateCompareState(X){this._compareState={...this._compareState,...X},this.emit("compare-state-change",this._compareState)}updateHistoryState(X){this._historyState={...this._historyState,...X},this.emit("history-state-change",this._historyState)}updateCompareSelectionState(X){this._compareSelectionState={...this._compareSelectionState,...X},this.emit("compare-selection-change",this._compareSelectionState)}startWatching(){let X=d8.join(this.repoPath,".git");if(!Y9.existsSync(X))return;let Y=d8.join(X,"index"),$=d8.join(X,"HEAD"),J=d8.join(X,"refs");this.gitWatcher=X9([Y,$,J],{persistent:!0,ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}}),this.workingDirWatcher=X9(this.repoPath,{persistent:!0,ignoreInitial:!0,ignored:["**/node_modules/**","**/.git/**","**/dist/**","**/build/**","**/*.log","**/.DS_Store"],awaitWriteFinish:{stabilityThreshold:100,pollInterval:50},depth:10});let Z=()=>this.scheduleRefresh();this.gitWatcher.on("change",Z),this.gitWatcher.on("add",Z),this.gitWatcher.on("unlink",Z),this.workingDirWatcher.on("change",Z),this.workingDirWatcher.on("add",Z),this.workingDirWatcher.on("unlink",Z)}dispose(){this.gitWatcher?.close(),this.workingDirWatcher?.close(),b4(this.repoPath)}scheduleRefresh(){this.queue.scheduleRefresh(()=>this.doRefresh())}async refresh(){await this.queue.enqueue(()=>this.doRefresh())}async doRefresh(){this.updateState({isLoading:!0,error:null});try{let X=await u4(this.repoPath);if(!X.isRepo){this.updateState({status:X,diff:null,stagedDiff:"",isLoading:!1,error:"Not a git repository"});return}let[Y,$]=await Promise.all([JY(this.repoPath),f8(this.repoPath,void 0,!1)]),J,Z=this._state.selectedFile;if(Z){let K=X.files.find((Q)=>Q.path===Z.path&&Q.staged===Z.staged);if(K)if(K.status==="untracked")J=await $Y(this.repoPath,K.path);else J=await f8(this.repoPath,K.path,K.staged);else J=$.raw?$:Y,this.updateState({selectedFile:null})}else if($.raw)J=$;else if(Y.raw)J=Y;else J={raw:"",lines:[]};this.updateState({status:X,diff:J,stagedDiff:Y.raw,isLoading:!1})}catch(X){this.updateState({isLoading:!1,error:X instanceof Error?X.message:"Unknown error"})}}async selectFile(X){if(this.updateState({selectedFile:X}),!this._state.status?.isRepo)return;await this.queue.enqueue(async()=>{if(X){let Y;if(X.status==="untracked")Y=await $Y(this.repoPath,X.path);else Y=await f8(this.repoPath,X.path,X.staged);this.updateState({diff:Y})}else{let Y=await JY(this.repoPath);this.updateState({diff:Y})}})}async stage(X){let Y=this._state.status;if(Y)this.updateState({status:{...Y,files:Y.files.map(($)=>$.path===X.path&&!$.staged?{...$,staged:!0}:$)}});try{await this.queue.enqueueMutation(()=>h4(this.repoPath,X.path)),this.scheduleRefresh()}catch($){await this.refresh(),this.updateState({error:`Failed to stage ${X.path}: ${$ instanceof Error?$.message:String($)}`})}}async unstage(X){let Y=this._state.status;if(Y)this.updateState({status:{...Y,files:Y.files.map(($)=>$.path===X.path&&$.staged?{...$,staged:!1}:$)}});try{await this.queue.enqueueMutation(()=>m4(this.repoPath,X.path)),this.scheduleRefresh()}catch($){await this.refresh(),this.updateState({error:`Failed to unstage ${X.path}: ${$ instanceof Error?$.message:String($)}`})}}async discard(X){if(X.staged||X.status==="untracked")return;try{await this.queue.enqueueMutation(()=>c4(this.repoPath,X.path)),await this.refresh()}catch(Y){this.updateState({error:`Failed to discard ${X.path}: ${Y instanceof Error?Y.message:String(Y)}`})}}async stageAll(){try{await this.queue.enqueueMutation(()=>f4(this.repoPath)),await this.refresh()}catch(X){this.updateState({error:`Failed to stage all: ${X instanceof Error?X.message:String(X)}`})}}async unstageAll(){try{await this.queue.enqueueMutation(()=>d4(this.repoPath)),await this.refresh()}catch(X){this.updateState({error:`Failed to unstage all: ${X instanceof Error?X.message:String(X)}`})}}async commit(X,Y=!1){try{await this.queue.enqueue(()=>l4(this.repoPath,X,Y)),await this.refresh()}catch($){this.updateState({error:`Failed to commit: ${$ instanceof Error?$.message:String($)}`})}}async getHeadCommitMessage(){return this.queue.enqueue(()=>n4(this.repoPath))}async refreshCompareDiff(X=!1){this.updateCompareState({compareLoading:!0,compareError:null});try{await this.queue.enqueue(async()=>{let Y=this._compareState.compareBaseBranch;if(!Y)Y=t4(this.repoPath)??await o4(this.repoPath),this.updateCompareState({compareBaseBranch:Y});if(Y){let $=X?await s4(this.repoPath,Y):await KY(this.repoPath,Y);this.updateCompareState({compareDiff:$,compareLoading:!1})}else this.updateCompareState({compareDiff:null,compareLoading:!1,compareError:"No base branch found"})})}catch(Y){this.updateCompareState({compareLoading:!1,compareError:`Failed to load compare diff: ${Y instanceof Error?Y.message:String(Y)}`})}}async getCandidateBaseBranches(){return ZY(this.repoPath)}async setCompareBaseBranch(X,Y=!1){this.updateCompareState({compareBaseBranch:X}),e4(this.repoPath,X),await this.refreshCompareDiff(Y)}async selectHistoryCommit(X){if(this.updateHistoryState({selectedCommit:X,commitDiff:null}),!X)return;try{await this.queue.enqueue(async()=>{let Y=await QY(this.repoPath,X.hash);this.updateHistoryState({commitDiff:Y})})}catch(Y){this.updateState({error:`Failed to load commit diff: ${Y instanceof Error?Y.message:String(Y)}`})}}async selectCompareCommit(X){let Y=this._compareState.compareDiff;if(!Y||X<0||X>=Y.commits.length){this.updateCompareSelectionState({type:null,index:0,diff:null});return}let $=Y.commits[X];this.updateCompareSelectionState({type:"commit",index:X,diff:null});try{await this.queue.enqueue(async()=>{let J=await QY(this.repoPath,$.hash);this.updateCompareSelectionState({diff:J})})}catch(J){this.updateState({error:`Failed to load commit diff: ${J instanceof Error?J.message:String(J)}`})}}selectCompareFile(X){let Y=this._compareState.compareDiff;if(!Y||X<0||X>=Y.files.length){this.updateCompareSelectionState({type:null,index:0,diff:null});return}let $=Y.files[X];this.updateCompareSelectionState({type:"file",index:X,diff:$.diff})}}var EX=new Map;function J9(X){let Y=EX.get(X);if(!Y)Y=new $9(X),EX.set(X,Y);return Y}function Z9(X){let Y=EX.get(X);if(Y)Y.dispose(),EX.delete(X)}function K9(X){let[Y,$]=MX({status:null,diff:null,stagedDiff:"",selectedFile:null,isLoading:!1,error:null}),[J,Z]=MX({compareDiff:null,compareBaseBranch:null,compareLoading:!1,compareError:null}),[K,Q]=MX({selectedCommit:null,commitDiff:null}),[V,G]=MX({type:null,index:0,diff:null}),q=GJ(null);UJ(()=>{if(!X){$({status:null,diff:null,stagedDiff:"",selectedFile:null,isLoading:!1,error:null});return}let W=J9(X);q.current=W;let C=(p)=>{$(p)},b=(p)=>{Z(p)},w=(p)=>{Q(p)},g=(p)=>{G(p)};return W.on("state-change",C),W.on("compare-state-change",b),W.on("history-state-change",w),W.on("compare-selection-change",g),W.startWatching(),W.refresh(),()=>{W.off("state-change",C),W.off("compare-state-change",b),W.off("history-state-change",w),W.off("compare-selection-change",g),Z9(X),q.current=null}},[X]);let z=$0((W)=>{q.current?.selectFile(W)},[]),N=$0(async(W)=>{await q.current?.stage(W)},[]),A=$0(async(W)=>{await q.current?.unstage(W)},[]),E=$0(async(W)=>{await q.current?.discard(W)},[]),U=$0(async()=>{await q.current?.stageAll()},[]),M=$0(async()=>{await q.current?.unstageAll()},[]),O=$0(async(W,C=!1)=>{await q.current?.commit(W,C)},[]),F=$0(async()=>{await q.current?.refresh()},[]),k=$0(async()=>{return q.current?.getHeadCommitMessage()??""},[]),H=$0(async(W=!1)=>{await q.current?.refreshCompareDiff(W)},[]),B=$0(async()=>{return q.current?.getCandidateBaseBranches()??[]},[]),L=$0(async(W,C=!1)=>{await q.current?.setCompareBaseBranch(W,C)},[]),R=$0(async(W)=>{await q.current?.selectHistoryCommit(W)},[]),S=$0(async(W)=>{await q.current?.selectCompareCommit(W)},[]),P=$0((W)=>{q.current?.selectCompareFile(W)},[]);return{status:Y.status,diff:Y.diff,stagedDiff:Y.stagedDiff,selectedFile:Y.selectedFile,isLoading:Y.isLoading,error:Y.error,selectFile:z,stage:N,unstage:A,discard:E,stageAll:U,unstageAll:M,commit:O,refresh:F,getHeadCommitMessage:k,compareDiff:J.compareDiff,compareBaseBranch:J.compareBaseBranch,compareLoading:J.compareLoading,compareError:J.compareError,refreshCompareDiff:H,getCandidateBaseBranches:B,setCompareBaseBranch:L,historySelectedCommit:K.selectedCommit,historyCommitDiff:K.commitDiff,selectHistoryCommit:R,compareSelectionType:V.type,compareSelectionIndex:V.index,compareSelectionDiff:V.diff,selectCompareCommit:S,selectCompareFile:P}}import{useInput as NJ}from"ink";function Q9(X,Y,$){NJ((J,Z)=>{if($)return;if(Z.ctrl&&J==="c"){X.onQuit();return}if(J==="q"){X.onQuit();return}if(J==="j"||Z.downArrow){X.onNavigateDown();return}if(J==="k"||Z.upArrow){X.onNavigateUp();return}if(Z.tab){X.onTogglePane();return}if(J==="1"){X.onSwitchTab("diff");return}if(J==="2"){X.onSwitchTab("commit");return}if(J==="3"){X.onSwitchTab("history");return}if(J==="4"){X.onSwitchTab("compare");return}if(J==="5"){X.onSwitchTab("explorer");return}if(J==="u"&&X.onToggleIncludeUncommitted){X.onToggleIncludeUncommitted();return}if(J==="b"&&X.onCycleBaseBranch){X.onCycleBaseBranch();return}if(J==="t"&&X.onOpenThemePicker){X.onOpenThemePicker();return}if(J==="?"&&X.onOpenHotkeysModal){X.onOpenHotkeysModal();return}if(J==="["&&X.onShrinkTopPane){X.onShrinkTopPane();return}if(J==="]"&&X.onGrowTopPane){X.onGrowTopPane();return}if(J==="m"&&X.onToggleMouse){X.onToggleMouse();return}if(J==="f"&&X.onToggleFollow){X.onToggleFollow();return}if(J==="a"&&X.onToggleAutoTab){X.onToggleAutoTab();return}if(J==="w"&&X.onToggleWrap){X.onToggleWrap();return}if(J==="."&&X.onToggleMiddleDots){X.onToggleMiddleDots();return}if(Z.ctrl&&J==="h"&&X.onToggleHideHiddenFiles){X.onToggleHideHiddenFiles();return}if(Z.ctrl&&J==="g"&&X.onToggleHideGitignored){X.onToggleHideGitignored();return}if(Z.ctrl&&J==="s"){X.onStage();return}if(Z.ctrl&&J==="u"){X.onUnstage();return}if(Z.ctrl&&J==="a"){X.onStageAll();return}if(Z.ctrl&&J==="z"){X.onUnstageAll();return}if(J==="c"){X.onCommit();return}if(Z.ctrl&&J==="r"){X.onRefresh();return}if(J==="r"){X.onRefresh();return}if(X.onExplorerEnter&&Z.return){X.onExplorerEnter();return}if(X.onExplorerBack&&(Z.backspace||Z.delete||J==="h")){X.onExplorerBack();return}if(Z.return||J===" "){X.onSelect();return}})}import{useEffect as LX,useState as AJ,useCallback as BJ,useRef as q9}from"react";import{useStdin as EJ}from"ink";function z9(X,Y=!1){let{stdin:$,setRawMode:J}=EJ(),[Z,K]=AJ(!0),Q=q9(X);LX(()=>{Q.current=X});let V=BJ(()=>{K((q)=>!q)},[]),G=q9(Z);return LX(()=>{G.current=Z},[Z]),LX(()=>{if(!Y&&Z)process.stdout.write("\x1B[?1000h"),process.stdout.write("\x1B[?1006h");else process.stdout.write("\x1B[?1006l"),process.stdout.write("\x1B[?1000l")},[Y,Z]),LX(()=>{if(!$||!J)return;let q=(z)=>{let N=z.toString(),A=N.match(/\x1b\[<(\d+);(\d+);(\d+)([Mm])/);if(A){let U=parseInt(A[1],10),M=parseInt(A[2],10),O=parseInt(A[3],10),F=A[4]==="m";if(U>=64&&U<96){if(G.current){let k=U===64?"scroll-up":"scroll-down";Q.current({x:M,y:O,type:k,button:"none"})}}else if(F&&U>=0&&U<3){let k=U===0?"left":U===1?"middle":"right";Q.current({x:M,y:O,type:"click",button:k})}return}let E=N.match(/\x1b\[M(.)(.)(.)/);if(E){let U=E[1].charCodeAt(0)-32,M=E[2].charCodeAt(0)-32,O=E[3].charCodeAt(0)-32;if(U>=64){if(G.current){let F=U===64?"scroll-up":"scroll-down";Q.current({x:M,y:O,type:F,button:"none"})}}else if(U>=0&&U<3){let F=U===0?"left":U===1?"middle":"right";Q.current({x:M,y:O,type:"click",button:F})}}};return $.on("data",q),()=>{$.off("data",q),process.stdout.write("\x1B[?1006l"),process.stdout.write("\x1B[?1000l")}},[$,J]),{mouseEnabled:Z,toggleMouse:V}}import{useState as MJ,useEffect as LJ}from"react";function V9(){let[X,Y]=MJ({rows:process.stdout.rows??24,columns:process.stdout.columns??80});return LJ(()=>{let $=()=>{Y({rows:process.stdout.rows??24,columns:process.stdout.columns??80})};return process.stdout.on("resize",$),()=>{process.stdout.off("resize",$)}},[]),X}import{useState as c8,useEffect as qY,useMemo as O9,useCallback as F8}from"react";function U9(X){let{modifiedCount:Y,untrackedCount:$,stagedCount:J}=b8(X),Z=0;if(Y>0)Z+=1+Y;if($>0){if(Y>0)Z+=1;Z+=1+$}if(J>0){if(Y>0||$>0)Z+=1;Z+=1+J}return Z}function G9(X,Y,$,J){let Z=0;if(X<Y)return 1+X;if(Y>0)Z+=1+Y;let K=Y;if(X<K+$){let G=X-K;if(Y>0)Z+=1;return Z+1+G}if($>0){if(Y>0)Z+=1;Z+=1+$}let Q=Y+$,V=X-Q;if(Y>0||$>0)Z+=1;return Z+1+V}function N9(X,Y,$){if(X<Y)return Math.max(0,X-1);else if(X>=Y+$)return X-$+1;return Y}function A9(X,Y,$,J=1){let Z=J+2,K=J+1+X,Q=K+1,V=K+2,G=V+Y-1;return{stagingPaneStart:Z,fileListEnd:K,separatorRow:Q,diffPaneStart:V,diffPaneEnd:G,footerRow:$}}function B9(X,Y,$,J,Z){if(X<J+1||X>Z)return-1;let K=X-(J+1)+Y,{modified:Q,untracked:V,staged:G}=g0($),q=0,z=0;if(Q.length>0){q++;for(let N=0;N<Q.length;N++){if(K===q)return z;q++,z++}}if(V.length>0){if(Q.length>0)q++;q++;for(let N=0;N<V.length;N++){if(K===q)return z;q++,z++}}if(G.length>0){if(Q.length>0||V.length>0)q++;q++;for(let N=0;N<G.length;N++){if(K===q)return z;q++,z++}}return-1}function OJ(X){let Y=X-51;return{diffStart:Y,diffEnd:Y+6,commitStart:Y+8,commitEnd:Y+16,historyStart:Y+18,historyEnd:Y+27,compareStart:Y+29,compareEnd:Y+38,explorerStart:Y+40,explorerEnd:Y+50}}function E9(X,Y){let $=OJ(Y);if(X>=$.diffStart&&X<=$.diffEnd)return"diff";else if(X>=$.commitStart&&X<=$.commitEnd)return"commit";else if(X>=$.historyStart&&X<=$.historyEnd)return"history";else if(X>=$.compareStart&&X<=$.compareEnd)return"compare";else if(X>=$.explorerStart&&X<=$.explorerEnd)return"explorer";return null}function M9(X){return X<=6}function OX(X,Y,$){return X>=Y&&X<=$}function L9(X){if(X===1)return"hotkeys";if(X>=3&&X<=10)return"mouse-mode";if(X>=12&&X<=17)return"auto-tab";if(X>=19&&X<=24)return"wrap";return null}var kJ=5,k9={diff:0.4,commit:0.4,history:0.5,compare:0.5,explorer:0.4},zY=0.05;function W9(X,Y,$,J,Z,K="diff",Q,V,G=0){let q=X-kJ-G,[z,N]=c8(V??null),A=z??k9[K],{topPaneHeight:E,bottomPaneHeight:U}=O9(()=>{let v=q-5,y=Math.floor(q*A),T=Math.max(5,Math.min(y,v)),j=q-T;return{topPaneHeight:T,bottomPaneHeight:j}},[q,A]),M=F8((_)=>{let v=Math.max(0.15,Math.min(0.85,_));N(v)},[]),O=F8((_)=>{let v=z??k9[K],y=Math.max(0.15,Math.min(0.85,v+_));N(y)},[z,K]),F=A,k=G+1,H=O9(()=>A9(E,U,X,k),[E,U,X,k]),[B,L]=c8(0),[R,S]=c8(0),[P,W]=c8(0),[C,b]=c8(0);qY(()=>{L(0)},[$.length]),qY(()=>{S(0)},[Z]),qY(()=>{let{modifiedCount:_,untrackedCount:v,stagedCount:y}=b8($),T=G9(J,_,v,y),j=E-1;L((x)=>{return N9(T,x,j)})},[J,$,E]);let w=F8((_,v=3,y=0)=>{let T=U-1,x=y>T?T-2:T,D=Math.max(0,y-x);S((y8)=>{if(_==="up")return Math.max(0,y8-v);else return Math.min(D,y8+v)})},[U]),g=F8((_,v=3)=>{let y=U9($),T=E-1,j=Math.max(0,y-T);L((x)=>{if(_==="up")return Math.max(0,x-v);else return Math.min(j,x+v)})},[$,E]),p=F8((_,v=0,y=3)=>{let T=E8(v,E-1);W((j)=>{if(_==="up")return Math.max(0,j-y);else return Math.min(T,j+y)})},[E]),f=F8((_,v,y=3)=>{let T=E8(v,E-1);b((j)=>{if(_==="up")return Math.max(0,j-y);else return Math.min(T,j+y)})},[E]);return{topPaneHeight:E,bottomPaneHeight:U,contentHeight:q,paneBoundaries:H,splitRatio:F,setSplitRatio:M,adjustSplitRatio:O,fileListScrollOffset:B,diffScrollOffset:R,historyScrollOffset:P,compareScrollOffset:C,setFileListScrollOffset:L,setDiffScrollOffset:S,setHistoryScrollOffset:W,setCompareScrollOffset:b,scrollDiff:w,scrollFileList:g,scrollHistory:p,scrollCompare:f}}import{useState as H9,useEffect as I9,useCallback as F9,useMemo as R9}from"react";function D9({repoPath:X,isActive:Y,selectHistoryCommit:$,historyCommitDiff:J,historySelectedCommit:Z,topPaneHeight:K,historyScrollOffset:Q,setHistoryScrollOffset:V,setDiffScrollOffset:G,status:q,wrapMode:z,terminalWidth:N}){let[A,E]=H9([]),[U,M]=H9(0);I9(()=>{if(X&&Y)r4(X,100).then(E)},[X,Y,q]),I9(()=>{if(Y&&A.length>0){let B=A[U];if(B)$(B),G(0)}},[Y,A,U,$,G]);let O=R9(()=>{let B=GX(Z,J);if(!z)return B.length;let L=R0(B),R=N-L-5;return L8(B,R,!0)},[Z,J,z,N]),F=R9(()=>A.length,[A]),k=F9(()=>{M((B)=>{let L=Math.max(0,B-1);if(L<Q)V(L);return L})},[Q,V]),H=F9(()=>{M((B)=>{let L=Math.min(A.length-1,B+1),R=Q+K-2;if(L>=R)V(Q+1);return L})},[A.length,Q,K,V]);return{commits:A,historySelectedIndex:U,setHistorySelectedIndex:M,historyDiffTotalRows:O,navigateHistoryUp:k,navigateHistoryDown:H,historyTotalRows:F}}import{useState as l8,useEffect as kX,useCallback as m0,useMemo as _9,useRef as WJ}from"react";function v9({repoPath:X,isActive:Y,compareDiff:$,refreshCompareDiff:J,getCandidateBaseBranches:Z,setCompareBaseBranch:K,selectCompareCommit:Q,topPaneHeight:V,compareScrollOffset:G,setCompareScrollOffset:q,setDiffScrollOffset:z,status:N,wrapMode:A,terminalWidth:E}){let[U,M]=l8(!0),[O,F]=l8(null),[k,H]=l8(0),B=WJ(!1),[L,R]=l8([]),[S,P]=l8(!1);kX(()=>{if(X&&Y)J(U)},[X,Y,N,J,U]),kX(()=>{if(X&&Y)Z().then(R)},[X,Y,Z]),kX(()=>{if(Y)B.current=!1,F(null),z(0)},[Y,z]),kX(()=>{if(Y&&$&&B.current){let T=$.commits.length,j=$.files.length;if(k<T)F({type:"commit",index:k}),Q(k),z(0);else if(k<T+j){let x=k-T;F({type:"file",index:x});let D=aY($,x);z(D)}}},[Y,$,k,Q,z]);let W=_9(()=>{if(!$)return 0;return $.commits.length+$.files.length},[$]),C=_9(()=>{let T=NX($);if(!A)return T.length;let j=R0(T),x=E-j-5;return L8(T,x,!0)},[$,A,E]),b=m0(()=>{M((T)=>!T)},[]),w=m0(()=>{P(!0)},[]),g=m0(()=>{P(!1)},[]),p=m0((T)=>{P(!1),K(T,U)},[K,U]),f=m0(()=>{B.current=!0},[]),_=m0(()=>{B.current=!0,H((T)=>{let j=Math.max(0,T-1);if(j<G)q(j);return j})},[G,q]),v=m0(()=>{B.current=!0,H((T)=>{let j=Math.min(W-1,T+1),x=G+V-2;if(j>=x)q(G+1);return j})},[W,G,V,q]),y=m0((T)=>{if(!$)return-1;return lX(T,$.commits.length,$.files.length)},[$]);return{includeUncommitted:U,compareListSelection:O,compareSelectedIndex:k,baseBranchCandidates:L,showBaseBranchPicker:S,compareTotalItems:W,compareDiffTotalRows:C,setCompareSelectedIndex:H,toggleIncludeUncommitted:b,openBaseBranchPicker:w,closeBaseBranchPicker:g,selectBaseBranch:p,navigateCompareUp:_,navigateCompareDown:v,markSelectionInitialized:f,getItemIndexFromRow:y}}import{useState as R8,useEffect as j9,useCallback as WX,useMemo as HJ}from"react";import*as HX from"node:fs";import*as D0 from"node:path";import{simpleGit as IJ}from"simple-git";var FJ=1048576,RJ=102400;function DJ(X){let Y=Math.min(X.length,8192);for(let $=0;$<Y;$++)if(X[$]===0)return!0;return!1}async function _J(X,Y){if(Y.length===0)return new Set;let $=IJ(X),J=new Set,Z=100;for(let K=0;K<Y.length;K+=Z){let Q=Y.slice(K,K+Z);try{let G=(await $.raw(["check-ignore",...Q])).trim().split(`
|
|
35
|
-
`).filter((q)=>q.length>0);for(let q of G)J.add(q)}catch{}}return J}function y9({repoPath:X,isActive:Y,topPaneHeight:$,explorerScrollOffset:J,setExplorerScrollOffset:Z,fileScrollOffset:K,setFileScrollOffset:Q,hideHiddenFiles:V,hideGitignored:G}){let[q,z]=R8(""),[N,A]=R8([]),[E,U]=R8(0),[M,O]=R8(null),[F,k]=R8(!1),[H,B]=R8(null);j9(()=>{if(!Y||!X)return;(async()=>{k(!0),B(null);try{let b=D0.join(X,q),w=await HX.promises.readdir(b,{withFileTypes:!0}),g=w.map((_)=>q?D0.join(q,_.name):_.name),p=G?await _J(X,g):new Set,f=w.filter((_)=>{if(V&&_.name.startsWith("."))return!1;if(G){let v=q?D0.join(q,_.name):_.name;if(p.has(v))return!1}return!0}).map((_)=>({name:_.name,path:q?D0.join(q,_.name):_.name,isDirectory:_.isDirectory()}));if(f.sort((_,v)=>{if(_.isDirectory&&!v.isDirectory)return-1;if(!_.isDirectory&&v.isDirectory)return 1;return _.name.localeCompare(v.name)}),q)f.unshift({name:"..",path:D0.dirname(q)||"",isDirectory:!0});A(f),U(0),Z(0)}catch(b){B(b instanceof Error?b.message:"Failed to read directory"),A([])}finally{k(!1)}})()},[X,q,Y,Z,V,G]),j9(()=>{if(!Y||!X||N.length===0){O(null);return}let C=N[E];if(!C||C.isDirectory){O(null);return}(async()=>{try{let w=D0.join(X,C.path),g=await HX.promises.stat(w);if(g.size>FJ){O({path:C.path,content:`File too large to display (${(g.size/1024/1024).toFixed(2)} MB).
|
|
36
|
-
Maximum size: 1 MB`,truncated:!0});return}let p=await HX.promises.readFile(w);if(DJ(p)){O({path:C.path,content:"Binary file - cannot display"});return}let f=p.toString("utf-8"),_=!1;if(g.size>RJ)f=`⚠ Large file (${(g.size/1024).toFixed(1)} KB)
|
|
2
|
+
import g9 from"neo-blessed";import a from"neo-blessed";var D7=0.05;function f9($,J,K,Z=1){let X=Z+4,Q=$-X,z=Math.floor(Q*K),q=Q-z;return{width:J,height:$,headerHeight:Z,topPaneHeight:z,bottomPaneHeight:q,footerRow:$-1}}function h9($,J,K,Z){let X=J+1,Q=X+K,z=Q+1,q=z+Z,Y=$-1;return{stagingPaneStart:X,fileListEnd:Q,diffPaneStart:z,diffPaneEnd:q,footerRow:Y}}class v7{screen;headerBox;topSeparator;topPane;middleSeparator;bottomPane;bottomSeparator;footerBox;_dimensions;_splitRatio;constructor($,J=0.4){this.screen=$,this._splitRatio=J,this._dimensions=this.calculateDimensions(),this.headerBox=this.createHeaderBox(),this.topSeparator=this.createSeparator(this._dimensions.headerHeight),this.topPane=this.createTopPane(),this.middleSeparator=this.createSeparator(this._dimensions.headerHeight+1+this._dimensions.topPaneHeight),this.bottomPane=this.createBottomPane(),this.bottomSeparator=this.createSeparator(this._dimensions.headerHeight+2+this._dimensions.topPaneHeight+this._dimensions.bottomPaneHeight),this.footerBox=this.createFooterBox(),$.on("resize",()=>this.onResize())}get dimensions(){return this._dimensions}get splitRatio(){return this._splitRatio}setSplitRatio($){this._splitRatio=Math.min(0.85,Math.max(0.15,$)),this.updateLayout()}adjustSplitRatio($){this.setSplitRatio(this._splitRatio+$)}calculateDimensions(){let $=this.screen.height||24,J=this.screen.width||80;return f9($,J,this._splitRatio)}createHeaderBox(){return a.box({parent:this.screen,top:0,left:0,width:"100%",height:this._dimensions.headerHeight,tags:!0})}createSeparator($){let J=this.screen.width||80;return a.box({parent:this.screen,top:$,left:0,width:"100%",height:1,content:"─".repeat(J),style:{fg:"gray"}})}createTopPane(){return a.box({parent:this.screen,top:this._dimensions.headerHeight+1,left:0,width:"100%",height:this._dimensions.topPaneHeight,tags:!0,scrollable:!0,alwaysScroll:!0,wrap:!1,scrollbar:{ch:" ",track:{bg:"gray"},style:{inverse:!0}}})}createBottomPane(){return a.box({parent:this.screen,top:this._dimensions.headerHeight+2+this._dimensions.topPaneHeight,left:0,width:"100%",height:this._dimensions.bottomPaneHeight,tags:!0,scrollable:!0,alwaysScroll:!0,wrap:!1,scrollbar:{ch:" ",track:{bg:"gray"},style:{inverse:!0}}})}createFooterBox(){return a.box({parent:this.screen,top:this._dimensions.footerRow,left:0,width:"100%",height:1,tags:!0})}onResize(){this._dimensions=this.calculateDimensions(),this.updateLayout()}updateLayout(){this._dimensions=this.calculateDimensions();let $=this.screen.width||80;this.headerBox.height=this._dimensions.headerHeight,this.headerBox.width=$,this.topSeparator.top=this._dimensions.headerHeight,this.topSeparator.width=$,this.topSeparator.setContent("─".repeat($)),this.topPane.top=this._dimensions.headerHeight+1,this.topPane.height=this._dimensions.topPaneHeight,this.topPane.width=$,this.middleSeparator.top=this._dimensions.headerHeight+1+this._dimensions.topPaneHeight,this.middleSeparator.width=$,this.middleSeparator.setContent("─".repeat($)),this.bottomPane.top=this._dimensions.headerHeight+2+this._dimensions.topPaneHeight,this.bottomPane.height=this._dimensions.bottomPaneHeight,this.bottomPane.width=$,this.bottomSeparator.top=this._dimensions.headerHeight+2+this._dimensions.topPaneHeight+this._dimensions.bottomPaneHeight,this.bottomSeparator.width=$,this.bottomSeparator.setContent("─".repeat($)),this.footerBox.top=this._dimensions.footerRow,this.footerBox.width=$}getPaneBoundaries(){return h9(this._dimensions.height,this._dimensions.headerHeight,this._dimensions.topPaneHeight,this._dimensions.bottomPaneHeight)}screenYToTopPaneRow($){let J=this._dimensions.headerHeight+1,K=J+this._dimensions.topPaneHeight;if($<J||$>=K)return-1;return $-J}screenYToBottomPaneRow($){let J=this._dimensions.headerHeight+2+this._dimensions.topPaneHeight,K=J+this._dimensions.bottomPaneHeight;if($<J||$>=K)return-1;return $-J}get topPaneTop(){return this._dimensions.headerHeight+1}get bottomPaneTop(){return this._dimensions.headerHeight+2+this._dimensions.topPaneHeight}}function s($){let J=$.filter((X)=>!X.staged&&X.status!=="untracked"),K=$.filter((X)=>!X.staged&&X.status==="untracked"),Z=$.filter((X)=>X.staged);return{modified:J,untracked:K,staged:Z,ordered:[...J,...K,...Z]}}function n($,J){let{modified:K,untracked:Z}=s($),X=K.length,Q=Z.length;if(J<X)return{category:"modified",categoryIndex:J};if(J<X+Q)return{category:"untracked",categoryIndex:J-X};return{category:"staged",categoryIndex:J-X-Q}}function Y8($,J,K){let{modified:Z,untracked:X,staged:Q,ordered:z}=s($);if(z.length===0)return 0;let Y={modified:Z,untracked:X,staged:Q}[J];if(Y.length===0)return z.length-1;let U=Math.min(K,Y.length-1);return{modified:0,untracked:Z.length,staged:Z.length+X.length}[J]+U}function A7($,J){if($.length<=J)return $;let Z=Math.max(J,20);if($.length<=Z)return $;let X=$.split("/");if(X.length===1){let B=Math.floor((Z-1)/2);return $.slice(0,B)+"…"+$.slice(-(Z-B-1))}let Q=X[X.length-1],z=X[0],q="/…/";if(z.length+q.length+Q.length>Z){let B=Z-2;if(Q.length>B){let G=Math.floor((B-1)/2);return"…/"+Q.slice(0,G)+"…"+Q.slice(-(B-G-1))}return"…/"+Q}let U=z,V=1;while(V<X.length-1){let B=X[V],G=U+"/"+B;if(G.length+q.length+Q.length<=Z)U=G,V++;else break}if(V===X.length-1)return $;return U+q+Q}function c9($){switch($){case"modified":return"M";case"added":return"A";case"deleted":return"D";case"untracked":return"?";case"renamed":return"R";case"copied":return"C";default:return" "}}function d9($){switch($){case"modified":return"yellow";case"added":return"green";case"deleted":return"red";case"untracked":return"gray";case"renamed":return"blue";case"copied":return"cyan";default:return"white"}}function l9($,J){if($===void 0&&J===void 0)return"";let K=[];if($!==void 0&&$>0)K.push(`{green-fg}+${$}{/green-fg}`);if(J!==void 0&&J>0)K.push(`{red-fg}-${J}{/red-fg}`);return K.length>0?" "+K.join(" "):""}function K7($){let{modified:J,untracked:K,staged:Z}=s($),X=[],Q=0;if(J.length>0)X.push({type:"header",content:"Modified:",headerColor:"yellow"}),J.forEach((z)=>{X.push({type:"file",file:z,fileIndex:Q++})});if(K.length>0){if(J.length>0)X.push({type:"spacer"});X.push({type:"header",content:"Untracked:",headerColor:"gray"}),K.forEach((z)=>{X.push({type:"file",file:z,fileIndex:Q++})})}if(Z.length>0){if(J.length>0||K.length>0)X.push({type:"spacer"});X.push({type:"header",content:"Staged:",headerColor:"green"}),Z.forEach((z)=>{X.push({type:"file",file:z,fileIndex:Q++})})}return X}function U8($,J,K,Z,X=0,Q){if($.length===0)return"{gray-fg} No changes{/gray-fg}";let z=K7($),q=Z-12,Y=Q?z.slice(X,X+Q):z.slice(X),U=[];for(let V of Y)if(V.type==="header")U.push(`{bold}{${V.headerColor}-fg}${V.content}{/${V.headerColor}-fg}{/bold}`);else if(V.type==="spacer")U.push("");else if(V.type==="file"&&V.file&&V.fileIndex!==void 0){let B=V.file,k=V.fileIndex===J&&K,j=c9(B.status),O=d9(B.status),D=B.staged?"[-]":"[+]",H=B.staged?"red":"green",A=l9(B.insertions,B.deletions),T=A.replace(/\{[^}]+\}/g,"").length,_=q-T,M=A7(B.path,_),v="";if(k)v+="{cyan-fg}{bold}▸ {/bold}{/cyan-fg}";else v+=" ";if(v+=`{${H}-fg}${D}{/${H}-fg} `,v+=`{${O}-fg}${j}{/${O}-fg} `,k)v+=`{cyan-fg}{inverse}${M}{/inverse}{/cyan-fg}`;else v+=M;if(B.originalPath)v+=` {gray-fg}← ${A7(B.originalPath,30)}{/gray-fg}`;v+=A,U.push(v)}return U.join(`
|
|
3
|
+
`)}function B8($){return K7($).length}function b($,J){let{ordered:K}=s($);return K[J]??null}function G8($,J){let Z=K7(J)[$];if(Z?.type==="file"&&Z.fileIndex!==void 0)return Z.fileIndex;return null}function T7($,J){let K=K7(J);for(let Z=0;Z<K.length;Z++)if(K[Z].type==="file"&&K[Z].fileIndex===$)return Z;return 0}function j8($,J,K){$.key(["q","C-c"],()=>{J.exit()}),$.key(["j","down"],()=>{if(K.hasActiveModal())return;J.navigateDown()}),$.key(["k","up"],()=>{if(K.hasActiveModal())return;J.navigateUp()});let Z=[["1","diff"],["2","commit"],["3","history"],["4","compare"],["5","explorer"]];for(let[X,Q]of Z)$.key([X],()=>{if(K.hasActiveModal())return;K.uiState.setTab(Q)});$.key(["tab"],()=>{if(K.hasActiveModal())return;K.uiState.togglePane()}),$.key(["s"],()=>{if(K.hasActiveModal())return;J.stageSelected()}),$.key(["S-u"],()=>{if(K.hasActiveModal())return;J.unstageSelected()}),$.key(["S-a"],()=>{if(K.hasActiveModal())return;J.stageAll()}),$.key(["S-z"],()=>{if(K.hasActiveModal())return;J.unstageAll()}),$.key(["enter","space"],()=>{if(K.hasActiveModal())return;if(K.getBottomTab()==="explorer"&&K.getCurrentPane()==="explorer")J.enterExplorerDirectory();else J.toggleSelected()}),$.key(["backspace"],()=>{if(K.hasActiveModal())return;if(K.getBottomTab()==="explorer"&&K.getCurrentPane()==="explorer")J.goExplorerUp()}),$.key(["g"],()=>{if(K.hasActiveModal())return;if(K.getBottomTab()==="explorer")K.explorerManager?.toggleShowOnlyChanges()}),$.key(["/"],()=>{if(K.hasActiveModal())return;if(K.getBottomTab()==="explorer")J.openFileFinder()}),$.key(["c"],()=>{if(K.hasActiveModal())return;K.uiState.setTab("commit")}),$.key(["i"],()=>{if(K.getBottomTab()==="commit"&&!K.isCommitInputFocused())J.focusCommitInput()}),$.key(["a"],()=>{if(K.getBottomTab()==="commit"&&!K.isCommitInputFocused())K.commitFlowState.toggleAmend(),J.render();else K.uiState.toggleAutoTab()}),$.key(["escape"],()=>{if(K.getBottomTab()==="commit")if(K.isCommitInputFocused())J.unfocusCommitInput();else K.uiState.setTab("diff")}),$.key(["r"],()=>J.refresh()),$.key(["w"],()=>K.uiState.toggleWrapMode()),$.key(["m"],()=>J.toggleMouseMode()),$.key(["S-t"],()=>K.uiState.toggleAutoTab()),$.key(["-","_","["],()=>{K.uiState.adjustSplitRatio(-D7),K.layout.setSplitRatio(K.uiState.state.splitRatio),J.render()}),$.key(["=","+","]"],()=>{K.uiState.adjustSplitRatio(D7),K.layout.setSplitRatio(K.uiState.state.splitRatio),J.render()}),$.key(["t"],()=>K.uiState.openModal("theme")),$.key(["?"],()=>K.uiState.toggleModal("hotkeys")),$.key(["f"],()=>J.toggleFollow()),$.key(["b"],()=>{if(K.getBottomTab()==="compare")K.uiState.openModal("baseBranch")}),$.key(["u"],()=>{if(K.getBottomTab()==="compare"){K.uiState.toggleIncludeUncommitted();let X=K.uiState.state.includeUncommitted;K.gitManager?.refreshCompareDiff(X)}}),$.key(["d"],()=>{if(K.getBottomTab()==="diff"){let X=K.getStatusFiles(),Q=b(X,K.getSelectedIndex());if(Q&&!Q.staged&&Q.status!=="untracked")J.showDiscardConfirm(Q)}})}function Z7($){let K=new Date().getTime()-$.getTime(),Z=Math.floor(K/3600000),X=Math.floor(K/86400000);if(Z<1)return`${Math.floor(K/60000)}m ago`;else if(Z<48)return`${Z}h ago`;else if(X<=14)return`${X}d ago`;else return $.toLocaleDateString("en-US",{month:"short",day:"numeric"})}function k8($){return $.toLocaleString("en-US",{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}function o9($,J){if($.length<=J)return $;if(J<=3)return $.slice(0,J);return $.slice(0,J-3)+"..."}function X7($,J,K,Z=20){let X=J||"",Q=Math.max(0,K-Z-1),z=X;if(z.length>Q&&Q>3)z=z.slice(0,Q-3)+"...";else if(z.length>Q)z="";let q=z?z.length+1:0,Y=Math.max(Z,K-q);return{displayMessage:o9($,Y),displayRefs:z}}function _8($,J,K,Z,X=0,Q){if($.length===0)return"{gray-fg}No commits yet{/gray-fg}";let z=Q?$.slice(X,X+Q):$.slice(X),q=[];for(let Y=0;Y<z.length;Y++){let U=z[Y],G=X+Y===J&&K,k=Z7(U.date),j=11+k.length+2+2,O=Math.max(10,Z-j),{displayMessage:D,displayRefs:H}=X7(U.message,U.refs,O),A="";if(G)A+="{cyan-fg}{bold}▸ {/bold}{/cyan-fg}";else A+=" ";if(A+=`{yellow-fg}${U.shortHash}{/yellow-fg} `,G)A+=`{cyan-fg}{inverse}${N7(D)}{/inverse}{/cyan-fg}`;else A+=N7(D);if(A+=` {gray-fg}(${k}){/gray-fg}`,H)A+=` {green-fg}${N7(H)}{/green-fg}`;q.push(A)}return q.join(`
|
|
4
|
+
`)}function N7($){return $.replace(/\{/g,"{{").replace(/\}/g,"}}")}function O8($,J){return $[J]??null}function M8($){let J={name:"",fullPath:"",isDirectory:!0,children:[],depth:0};for(let K=0;K<$.length;K++){let X=$[K].path.split("/"),Q=J;for(let z=0;z<X.length;z++){let q=X[z],Y=z===X.length-1,U=X.slice(0,z+1).join("/"),V=Q.children.find((B)=>B.name===q&&B.isDirectory===!Y);if(!V)V={name:q,fullPath:U,isDirectory:!Y,children:[],depth:Q.depth+1,fileIndex:Y?K:void 0},Q.children.push(V);Q=V}}return H8(J),v8(J),J}function H8($){for(let J of $.children)H8(J);for(let J=0;J<$.children.length;J++){let K=$.children[J];while(K.isDirectory&&K.children.length===1&&K.children[0].isDirectory){let Z=K.children[0];K.name=`${K.name}/${Z.name}`,K.fullPath=Z.fullPath,K.children=Z.children,D8(K,K.depth)}}}function D8($,J){$.depth=J;for(let K of $.children)D8(K,J+1)}function v8($){$.children.sort((J,K)=>{if(J.isDirectory&&!K.isDirectory)return-1;if(!J.isDirectory&&K.isDirectory)return 1;return J.name.localeCompare(K.name)});for(let J of $.children)v8(J)}function A8($){let J=[];function K(Z,X){for(let Q=0;Q<Z.children.length;Q++){let z=Z.children[Q],q=Q===Z.children.length-1;if(J.push({type:z.isDirectory?"directory":"file",name:z.name,fullPath:z.fullPath,depth:z.depth-1,fileIndex:z.fileIndex,isLast:q,parentIsLast:[...X]}),z.isDirectory)K(z,[...X,q])}}return K($,[]),J}function W7($){let J="";for(let K=0;K<$.depth;K++)if($.parentIsLast[K])J+=" ";else J+="│ ";if($.depth>=0)if($.isLast)J+="└ ";else J+="├ ";return J}var L="\x1B[0m",r9="\x1B[1m",d="\x1B[90m",L7="\x1B[36m",N8="\x1B[33m",E7="\x1B[32m",T8="\x1B[31m",W8="\x1B[34m",F7="\x1B[35m",F8="\x1B[7m";function i($,J,K=!0,Z=!0){let X=[];if($.length>0){if(X.push({type:"section-header",sectionType:"commits"}),K)$.forEach((Q,z)=>{X.push({type:"commit",commitIndex:z,commit:Q})})}if(J.length>0){if($.length>0)X.push({type:"spacer"});if(X.push({type:"section-header",sectionType:"files"}),Z){let Q=M8(J),z=A8(Q);for(let q of z)if(q.type==="directory")X.push({type:"directory",treeRow:q});else{let Y=J[q.fileIndex];X.push({type:"file",fileIndex:q.fileIndex,file:Y,treeRow:q})}}}return X}function a9($,J,K,Z){let X=J&&K,Q=Z7($.date),z=13+Q.length+2,q=Math.max(10,Z-z),{displayMessage:Y,displayRefs:U}=X7($.message,$.refs,q),V=` ${N8}${$.shortHash}${L} `;if(X)V+=`${L7}${F8}${Y}${L}`;else V+=Y;if(V+=` ${d}(${Q})${L}`,U)V+=` ${E7}${U}${L}`;return`{escape}${V}{/escape}`}function s9($,J){let K=W7($),Z="▸ ",X=J-K.length-2-2,Q=$.name;if(Q.length>X)Q=Q.slice(0,X-1)+"…";return`{escape}${`${d}${K}${L}${W8}${"▸ "}${Q}${L}`}{/escape}`}function n9($,J,K,Z,X){let Q=K&&Z,z=$.isUncommitted??!1,q=W7(J),Y={added:E7,modified:N8,deleted:T8,renamed:W8},U={added:"+",modified:"●",deleted:"−",renamed:"→"},V=z?F7:Y[$.status],B=U[$.status],G=`(+${$.additions} -${$.deletions})`,k=z?" [uncommitted]":"",j=q.length+2+G.length+k.length+2,O=Math.max(5,X-j),D=J.name;if(D.length>O)D=D.slice(0,O-1)+"…";let H=`${d}${q}${L}`;if(H+=`${V}${B}${L} `,Q)H+=`${L7}${F8}${D}${L}`;else if(z)H+=`${F7}${D}${L}`;else H+=D;if(H+=` ${d}(${E7}+${$.additions}${L} ${T8}-${$.deletions}${d})${L}`,z)H+=` ${F7}[uncommitted]${L}`;return`{escape}${H}{/escape}`}function E8($,J,K,Z,X,Q=0,z){if($.length===0&&J.length===0)return"{gray-fg}No changes compared to base branch{/gray-fg}";let q=i($,J),Y=z?q.slice(Q,Q+z):q.slice(Q),U=[];for(let V of Y)if(V.type==="section-header"){let B=V.sectionType==="commits",G=B?$.length:J.length,k=B?"Commits":"Files";U.push(`{escape}${L7}${r9}▼ ${k}${L} ${d}(${G})${L}{/escape}`)}else if(V.type==="spacer")U.push("");else if(V.type==="commit"&&V.commit&&V.commitIndex!==void 0){let B=K?.type==="commit"&&K.index===V.commitIndex;U.push(a9(V.commit,B,Z,X))}else if(V.type==="directory"&&V.treeRow)U.push(s9(V.treeRow,X));else if(V.type==="file"&&V.file&&V.fileIndex!==void 0&&V.treeRow){let B=K?.type==="file"&&K.index===V.fileIndex;U.push(n9(V.file,V.treeRow,B,Z,X))}return U.join(`
|
|
5
|
+
`)}function L8($,J,K=!0,Z=!0){return i($,J,K,Z).length}function I7($,J,K,Z=!0,X=!0){let z=i(J,K,Z,X)[$];if(!z)return null;if(z.type==="commit"&&z.commitIndex!==void 0)return{type:"commit",index:z.commitIndex};if(z.type==="file"&&z.fileIndex!==void 0)return{type:"file",index:z.fileIndex};return null}function Q7($,J,K,Z=!0,X=!0){let Q=i(J,K,Z,X);for(let z=0;z<Q.length;z++){let q=Q[z];if($.type==="commit"&&q.type==="commit"&&q.commitIndex===$.index)return z;if($.type==="file"&&q.type==="file"&&q.fileIndex===$.index)return z}return 0}function R7($,J,K,Z){let X=i(J,K),Q=0;if($)Q=Q7($,J,K);let z=Z==="down"?1:-1,q=Q+z;while(q>=0&&q<X.length){let Y=I7(q,J,K);if(Y)return Y;q+=z}return $}function i9($){let J="";for(let K=0;K<$.depth;K++)if($.parentIsLast[K])J+=" ";else J+="│ ";if($.depth>0||$.parentIsLast.length===0)if($.isLast)J+="└ ";else J+="├ ";return J}function t9($){if(!$)return"";switch($){case"modified":return"M";case"added":return"A";case"deleted":return"D";case"untracked":return"?";case"renamed":return"R";case"copied":return"C";default:return""}}function e9($){if(!$)return"\x1B[0m";switch($){case"modified":return"\x1B[33m";case"added":return"\x1B[32m";case"deleted":return"\x1B[31m";case"untracked":return"\x1B[90m";case"renamed":return"\x1B[34m";case"copied":return"\x1B[35m";default:return"\x1B[0m"}}function I8($,J,K,Z,X=0,Q,z=!1,q=null){if(q)return`{red-fg}Error: ${$$(q)}{/red-fg}`;if(z)return"{gray-fg}Loading...{/gray-fg}";if($.length===0)return"{gray-fg}(empty directory){/gray-fg}";let Y=Q?$.slice(X,X+Q):$.slice(X),U=[];for(let V=0;V<Y.length;V++){let B=Y[V],j=X+V===J&&K,O=B.node,D=i9(B),H="";if(O.isDirectory)H=O.expanded?"▾ ":"▸ ";let A=t9(O.gitStatus),T=e9(O.gitStatus),_=A?`${T}${A}\x1B[0m `:"",M=O.isDirectory&&O.hasChangedChildren?`${"\x1B[33m"}●${"\x1B[0m"} `:"",v=D.length+H.length+(A?2:0)+(O.hasChangedChildren&&O.isDirectory?2:0),W=Math.max(5,Z-v-2),N=O.isDirectory?`${O.name}/`:O.name;if(N.length>W)N=N.slice(0,W-1)+"…";let F=`\x1B[90m${D}\x1B[0m`;if(O.isDirectory)if(F+=`\x1B[34m${H}\x1B[0m`,F+=M,j)F+=`\x1B[36m\x1B[1m\x1B[7m${N}\x1B[0m`;else F+=`\x1B[34m${N}\x1B[0m`;else if(F+=_,j)F+=`\x1B[36m\x1B[1m\x1B[7m${N}\x1B[0m`;else if(O.gitStatus)F+=`${T}${N}\x1B[0m`;else F+=N;U.push(`{escape}${F}{/escape}`)}return U.join(`
|
|
6
|
+
`)}function $$($){return $.replace(/\{/g,"{{").replace(/\}/g,"}}")}function R8($){return $.length}var J$={name:"dark",displayName:"Dark",colors:{addBg:"#022800",delBg:"#3D0100",addHighlight:"#044700",delHighlight:"#5C0200",text:"white",addLineNum:"#368F35",delLineNum:"#A14040",contextLineNum:"gray",addSymbol:"greenBright",delSymbol:"redBright"}},K$={name:"light",displayName:"Light",colors:{addBg:"#69db7c",delBg:"#ffa8b4",addHighlight:"#2f9d44",delHighlight:"#d1454b",text:"black",addLineNum:"#2f9d44",delLineNum:"#d1454b",contextLineNum:"#6c757d",addSymbol:"green",delSymbol:"red"}},Z$={name:"dark-colorblind",displayName:"Dark (colorblind)",colors:{addBg:"#004466",delBg:"#660000",addHighlight:"#0077b3",delHighlight:"#b30000",text:"white",addLineNum:"#0077b3",delLineNum:"#b30000",contextLineNum:"gray",addSymbol:"cyanBright",delSymbol:"redBright"}},X$={name:"light-colorblind",displayName:"Light (colorblind)",colors:{addBg:"#99ccff",delBg:"#ffcccc",addHighlight:"#3366cc",delHighlight:"#993333",text:"black",addLineNum:"#3366cc",delLineNum:"#993333",contextLineNum:"#6c757d",addSymbol:"blue",delSymbol:"red"}},Q$={name:"dark-ansi",displayName:"Dark (ANSI)",colors:{addBg:"green",delBg:"red",addHighlight:"greenBright",delHighlight:"redBright",text:"white",addLineNum:"greenBright",delLineNum:"redBright",contextLineNum:"gray",addSymbol:"greenBright",delSymbol:"redBright"}},z$={name:"light-ansi",displayName:"Light (ANSI)",colors:{addBg:"green",delBg:"red",addHighlight:"greenBright",delHighlight:"redBright",text:"black",addLineNum:"green",delLineNum:"red",contextLineNum:"gray",addSymbol:"green",delSymbol:"red"}},z7={dark:J$,light:K$,"dark-colorblind":Z$,"light-colorblind":X$,"dark-ansi":Q$,"light-ansi":z$},x=["dark","light","dark-colorblind","light-colorblind","dark-ansi","light-ansi"];function t($){return z7[$]??z7.dark}function q$($){return!($.startsWith("index ")||$.startsWith("--- ")||$.startsWith("+++ ")||$.startsWith("similarity index"))}function y8($){if($.type!=="header")return!0;return q$($.content)}function q7($,J,K=!0){if(J<=0)return[{text:$,isContinuation:!1}];if($.length<=J)return[{text:$,isContinuation:!1}];let Z=[],X=$,Q=!0;while(X.length>0){if(X.length<=J){Z.push({text:X,isContinuation:!Q});break}Z.push({text:X.slice(0,J),isContinuation:!Q}),X=X.slice(J),Q=!1}if(K)V$($,J,Z);return Z}function V$($,J,K){let Z=K.map((X)=>X.text).join("");if(Z!==$)throw Error(`[LineBreaking] Content was lost during breaking!
|
|
7
|
+
Original (${$.length} chars): "${$.slice(0,50)}${$.length>50?"...":""}"
|
|
8
|
+
Joined (${Z.length} chars): "${Z.slice(0,50)}${Z.length>50?"...":""}"`);for(let X=0;X<K.length;X++){let Q=K[X];if(Q.text.length>J&&J>=1)throw Error(`[LineBreaking] Segment ${X} exceeds maxWidth!
|
|
9
|
+
Segment length: ${Q.text.length}, maxWidth: ${J}
|
|
10
|
+
Segment: "${Q.text.slice(0,50)}${Q.text.length>50?"...":""}"`)}if(K.length>0&&K[0].isContinuation)throw Error("[LineBreaking] First segment incorrectly marked as continuation!");for(let X=1;X<K.length;X++)if(!K[X].isContinuation)throw Error(`[LineBreaking] Segment ${X} should be marked as continuation but isn't!`)}function y7($,J){if(J<=0)return 1;if($.length<=J)return 1;return Math.ceil($.length/J)}import l from"fast-diff";function C8($,J){if(!$||!J)return!1;let K=l($,J),Z=0,X=0;for(let[z,q]of K)if(X+=q.length,z===l.EQUAL)Z+=q.length;if(X===0)return!1;return Z/X>=0.5}function P8($,J){let K=l($,J),Z=[],X=[];for(let[Q,z]of K)if(Q===l.EQUAL)Z.push({text:z,type:"same"}),X.push({text:z,type:"same"});else if(Q===l.DELETE)Z.push({text:z,type:"changed"});else if(Q===l.INSERT)X.push({text:z,type:"changed"});return{oldSegments:Z,newSegments:X}}import{createEmphasize as Y$}from"emphasize";import{common as U$}from"lowlight";var P7=Y$(U$),B$={ts:"typescript",tsx:"typescript",js:"javascript",jsx:"javascript",mjs:"javascript",cjs:"javascript",html:"xml",htm:"xml",xml:"xml",svg:"xml",css:"css",scss:"scss",sass:"scss",less:"less",json:"json",yaml:"yaml",yml:"yaml",toml:"ini",sh:"bash",bash:"bash",zsh:"bash",fish:"bash",ps1:"powershell",bat:"dos",cmd:"dos",c:"c",h:"c",cpp:"cpp",hpp:"cpp",cc:"cpp",cxx:"cpp",rs:"rust",go:"go",zig:"zig",java:"java",kt:"kotlin",kts:"kotlin",scala:"scala",groovy:"groovy",gradle:"groovy",py:"python",rb:"ruby",pl:"perl",lua:"lua",php:"php",r:"r",hs:"haskell",ml:"ocaml",fs:"fsharp",fsx:"fsharp",ex:"elixir",exs:"elixir",erl:"erlang",clj:"clojure",cljs:"clojure",cs:"csharp",vb:"vbnet",md:"markdown",markdown:"markdown",rst:"plaintext",txt:"plaintext",Makefile:"makefile",Dockerfile:"dockerfile",cmake:"cmake",ini:"ini",conf:"ini",cfg:"ini",sql:"sql",vim:"vim",diff:"diff",patch:"diff"},S8={Makefile:"makefile",makefile:"makefile",GNUmakefile:"makefile",Dockerfile:"dockerfile",dockerfile:"dockerfile",Jenkinsfile:"groovy",Vagrantfile:"ruby",Gemfile:"ruby",Rakefile:"ruby",".gitignore":"plaintext",".gitattributes":"plaintext",".editorconfig":"ini",".prettierrc":"json",".eslintrc":"json","tsconfig.json":"json","package.json":"json","package-lock.json":"json","bun.lockb":"plaintext","yarn.lock":"yaml","pnpm-lock.yaml":"yaml","Cargo.toml":"ini","Cargo.lock":"ini","go.mod":"go","go.sum":"plaintext"},C7=null;function b8(){if(!C7)C7=new Set(P7.listLanguages());return C7}function V7($){if(!$)return null;let J=$.split("/").pop()??"";if(S8[J]){let X=S8[J];return b8().has(X)?X:null}let K=J.includes(".")?J.split(".").pop()?.toLowerCase():null;if(!K)return null;let Z=B$[K];if(!Z)return null;return b8().has(Z)?Z:null}function x8($,J){if(!$||!J)return $;try{return P7.highlight(J,$).value}catch{return $}}function S7($,J){if(!J||$.length===0)return $;try{let K=$.join(`
|
|
11
|
+
`);return P7.highlight(J,K).value.replace(/\x1b\[0m/g,"\x1B[39m").split(`
|
|
12
|
+
`)}catch{return $}}function w($){let J;if($.type==="addition"||$.type==="deletion")J=$.content.slice(1);else if($.type==="context")J=$.content.startsWith(" ")?$.content.slice(1):$.content;else J=$.content;return J.replace(/[\x00-\x08\x0a-\x1f\x7f]/g,"").replace(/\t/g," ")}function w8($){switch($.type){case"header":return{type:"diff-header",content:$.content};case"hunk":return{type:"diff-hunk",content:$.content};case"addition":return{type:"diff-add",lineNum:$.newLineNum,content:w($)};case"deletion":return{type:"diff-del",lineNum:$.oldLineNum,content:w($)};case"context":return{type:"diff-context",lineNum:$.oldLineNum??$.newLineNum,content:w($)}}}function G$($){let J=$.match(/^diff --git a\/.+ b\/(.+)$/);return J?J[1]:null}function b7($){if(!$)return[];let J=$.lines.filter(y8),K=[],Z=[],X=null,Q=0;while(Q<J.length){let z=J[Q];if(z.type==="header"){let G=G$(z.content);if(G){if(X)Z.push(X),K.push({type:"spacer"});X={language:V7(G),startRowIndex:K.length,oldContent:[],oldRowIndices:[],newContent:[],newRowIndices:[]}}K.push(w8(z)),Q++;continue}if(z.type==="hunk"){K.push(w8(z)),Q++;continue}if(z.type==="context"){let G=w(z),k=K.length;if(K.push({type:"diff-context",lineNum:z.oldLineNum??z.newLineNum,content:G}),X&&X.language)X.oldContent.push(G),X.oldRowIndices.push(k),X.newContent.push(G),X.newRowIndices.push(k);Q++;continue}let q=[];while(Q<J.length&&J[Q].type==="deletion")q.push(J[Q]),Q++;let Y=[];while(Q<J.length&&J[Q].type==="addition")Y.push(J[Q]),Q++;let U=new Map,V=new Map,B=Math.min(q.length,Y.length);for(let G=0;G<B;G++){let k=w(q[G]),j=w(Y[G]);if(C8(k,j)){let{oldSegments:O,newSegments:D}=P8(k,j);U.set(G,O),V.set(G,D)}}for(let G=0;G<q.length;G++){let k=q[G],j=w(k),O=U.get(G),D=K.length;if(K.push({type:"diff-del",lineNum:k.oldLineNum,content:j,...O&&{wordDiffSegments:O}}),X&&X.language&&!O)X.oldContent.push(j),X.oldRowIndices.push(D)}for(let G=0;G<Y.length;G++){let k=Y[G],j=w(k),O=V.get(G),D=K.length;if(K.push({type:"diff-add",lineNum:k.newLineNum,content:j,...O&&{wordDiffSegments:O}}),X&&X.language&&!O)X.newContent.push(j),X.newRowIndices.push(D)}}if(X)Z.push(X);for(let z of Z){if(!z.language)continue;if(z.oldContent.length>0){let q=S7(z.oldContent,z.language);for(let Y=0;Y<z.oldRowIndices.length;Y++){let U=z.oldRowIndices[Y],V=K[U],B=q[Y];if(B&&B!==V.content&&(V.type==="diff-del"||V.type==="diff-context"))V.highlighted=B}}if(z.newContent.length>0){let q=S7(z.newContent,z.language);for(let Y=0;Y<z.newRowIndices.length;Y++){let U=z.newRowIndices[Y],V=K[U],B=q[Y];if(B&&B!==V.content&&(V.type==="diff-add"||V.type==="diff-context"))V.highlighted=B}}}return K}function u8($,J){let K=[];if($){K.push({type:"commit-header",content:`commit ${$.hash}`}),K.push({type:"commit-header",content:`Author: ${$.author}`}),K.push({type:"commit-header",content:`Date: ${k8($.date)}`}),K.push({type:"spacer"});for(let Z of $.message.split(`
|
|
13
|
+
`))K.push({type:"commit-message",content:` ${Z}`});K.push({type:"spacer"})}return K.push(...b7(J)),K}function x7($){let J=0;for(let K of $)if("lineNum"in K&&K.lineNum!==void 0)J=Math.max(J,K.lineNum);return Math.max(3,String(J).length)}function w7($,J,K){if(!K)return $;let X=Math.max(10,J),Q=[];for(let z of $)if(z.type==="diff-add"||z.type==="diff-del"||z.type==="diff-context"){let q=z.content;if(!q||q.length<=X){Q.push(z);continue}let Y=q7(q,X);for(let U=0;U<Y.length;U++){let V=Y[U];Q.push({...z,content:V.text,lineNum:V.isContinuation?void 0:z.lineNum,isContinuation:V.isContinuation})}}else Q.push(z);return Q}var p8=/\x1b\[[0-9;]*m/g;function Y7($,J,K="…"){if(J<=0)return K;if(!$.includes("\x1B")&&$.length<=J)return $;if(!$.includes("\x1B")){if($.length<=J)return $;return $.slice(0,J-K.length)+K}let Z=[],X=0;p8.lastIndex=0;let Q;while((Q=p8.exec($))!==null){if(Q.index>X)Z.push({type:"text",content:$.slice(X,Q.index)});Z.push({type:"ansi",content:Q[0]}),X=Q.index+Q[0].length}if(X<$.length)Z.push({type:"text",content:$.slice(X)});let z="",q=0,Y=J-K.length,U=!1,V=!1;for(let B of Z)if(B.type==="ansi")z+=B.content,U=!0;else{let G=Y-q;if(G<=0){V=!0;break}if(B.content.length<=G)z+=B.content,q+=B.content.length;else{z+=B.content.slice(0,G),q+=G,V=!0;break}}if(V){if(U)z+="\x1B[0m";z+=K}return z}var E="\x1B[0m",j$="\x1B[1m",g8="\x1B[90m",u7="\x1B[36m",k$="\x1B[33m";function I($,J){if(J<=0||$.length<=J)return $;if(J<=1)return"…";return $.slice(0,J-1)+"…"}function p7($,J){if($===void 0)return" ".repeat(J);return String($).padStart(J," ")}function m8($){return $.replace(/\{/g,"{{").replace(/\}/g,"}}")}function U7($){let J=parseInt($.slice(1,3),16),K=parseInt($.slice(3,5),16),Z=parseInt($.slice(5,7),16);return`\x1B[48;2;${J};${K};${Z}m`}function f8($){let J=parseInt($.slice(1,3),16),K=parseInt($.slice(3,5),16),Z=parseInt($.slice(5,7),16);return`\x1B[38;2;${J};${K};${Z}m`}function h8($,J,K,Z,X,Q){let{colors:z}=X;switch($.type){case"diff-header":{let q=$.content;if(q.startsWith("diff --git")){let Y=q.match(/diff --git a\/.+ b\/(.+)$/);if(Y){let U=Z-6,V=I(Y[1],U);return`{escape}${j$}${u7}── ${V} ──${E}{/escape}`}}return`{escape}${g8}${I(q,Z)}${E}{/escape}`}case"diff-hunk":{let q=$.content.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/);if(q){let Y=parseInt(q[1],10),U=q[2]?parseInt(q[2],10):1,V=parseInt(q[3],10),B=q[4]?parseInt(q[4],10):1,G=q[5].trim(),k=Y+U-1,j=V+B-1,O=U===1?`${Y}`:`${Y}-${k}`,D=B===1?`${V}`:`${V}-${j}`,H=`Lines ${O} → ${D}`,A=Z-H.length-1,T=G&&A>3?" "+I(G,A):"";return`{escape}${u7}${H}${g8}${T}${E}{/escape}`}return`{escape}${u7}${I($.content,Z)}${E}{/escape}`}case"diff-add":{let q=$.isContinuation,Y=q?"»":"+",V=`${p7($.lineNum,J)} ${Y} `;if(X.name.includes("ansi")){let H=Q?$.content||"":I($.content||"",K),T=`${V}${H}`.padEnd(Z," ");return`{green-bg}{white-fg}${m8(T)}{/white-fg}{/green-bg}`}let B=U7(z.addBg),G=U7(z.addHighlight),k=f8("#ffffff");if($.wordDiffSegments&&!q){let H=$.content||"";if(!Q&&H.length>K){let M=I(H,K),W=`${V}${M}`.padEnd(Z," ");return`{escape}${B}${k}${W}${E}{/escape}`}let A="";for(let M of $.wordDiffSegments)if(M.type==="changed")A+=`${G}${M.text}${B}`;else A+=M.text;let T=V.length+H.length,_=" ".repeat(Math.max(0,Z-T));return`{escape}${B}${k}${V}${A}${_}${E}{/escape}`}if($.highlighted&&!q){let H=$.content||"";if(!Q&&H.length>K){let _=I(H,K),v=`${V}${_}`.padEnd(Z," ");return`{escape}${B}${k}${v}${E}{/escape}`}let A=V.length+H.length,T=" ".repeat(Math.max(0,Z-A));return`{escape}${B}${k}${V}${$.highlighted}${T}${E}{/escape}`}let j=Q?$.content||"":I($.content||"",K),D=`${V}${j}`.padEnd(Z," ");return`{escape}${B}${k}${D}${E}{/escape}`}case"diff-del":{let q=$.isContinuation,Y=q?"»":"-",V=`${p7($.lineNum,J)} ${Y} `;if(X.name.includes("ansi")){let H=Q?$.content||"":I($.content||"",K),T=`${V}${H}`.padEnd(Z," ");return`{red-bg}{white-fg}${m8(T)}{/white-fg}{/red-bg}`}let B=U7(z.delBg),G=U7(z.delHighlight),k=f8("#ffffff");if($.wordDiffSegments&&!q){let H=$.content||"";if(!Q&&H.length>K){let M=I(H,K),W=`${V}${M}`.padEnd(Z," ");return`{escape}${B}${k}${W}${E}{/escape}`}let A="";for(let M of $.wordDiffSegments)if(M.type==="changed")A+=`${G}${M.text}${B}`;else A+=M.text;let T=V.length+H.length,_=" ".repeat(Math.max(0,Z-T));return`{escape}${B}${k}${V}${A}${_}${E}{/escape}`}if($.highlighted&&!q){let H=$.content||"";if(!Q&&H.length>K){let _=I(H,K),v=`${V}${_}`.padEnd(Z," ");return`{escape}${B}${k}${v}${E}{/escape}`}let A=V.length+H.length,T=" ".repeat(Math.max(0,Z-A));return`{escape}${B}${k}${V}${$.highlighted}${T}${E}{/escape}`}let j=Q?$.content||"":I($.content||"",K),D=`${V}${j}`.padEnd(Z," ");return`{escape}${B}${k}${D}${E}{/escape}`}case"diff-context":{let q=$.isContinuation,Y=q?"»":" ",V=`${p7($.lineNum,J)} ${Y} `,B=$.content||"",G=`\x1B[90m${V}\x1B[0m`;if($.highlighted&&!q){let j=Q?$.highlighted:Y7($.highlighted,K);return`{escape}${G}${j}${E}{/escape}`}let k=Q?B:I(B,K);return`{escape}${G}${k}${E}{/escape}`}case"commit-header":return`{escape}${k$}${I($.content,Z)}${E}{/escape}`;case"commit-message":return`{escape}${I($.content,Z)}${E}{/escape}`;case"spacer":return""}}function g7($,J,K=0,Z,X="dark",Q=!1){let z=b7($);if(z.length===0)return{content:"{gray-fg}No diff to display{/gray-fg}",totalRows:0};let q=t(X),Y=x7(z),U=J-Y-5,V=J-2,B=w7(z,U,Q),G=B.length;return{content:(Z?B.slice(K,K+Z):B.slice(K)).map((O)=>h8(O,Y,U,V,q,Q)).join(`
|
|
14
|
+
`),totalRows:G}}function c8($,J,K,Z=0,X,Q="dark",z=!1){let q=u8($,J);if(q.length===0)return{content:"{gray-fg}No commit selected{/gray-fg}",totalRows:0};let Y=t(Q),U=x7(q),V=K-U-5,B=K-2,G=w7(q,V,z),k=G.length;return{content:(X?G.slice(Z,Z+X):G.slice(Z)).map((D)=>h8(D,U,V,B,Y,z)).join(`
|
|
15
|
+
`),totalRows:k}}function d8($,J,K){let Z=[],X="{bold}Commit Message{/bold}";if($.amend)X+=" {yellow-fg}(amending){/yellow-fg}";Z.push(X),Z.push("");let Q=$.inputFocused?"│":"│",z=$.inputFocused?"cyan":"gray",q=Math.max(20,K-6);Z.push(`{${z}-fg}┌${"─".repeat(q+2)}┐{/${z}-fg}`);let Y=$.message||($.inputFocused?"":"Press i or Enter to edit..."),U=$.message?"":"{gray-fg}",V=$.message?"":"{/gray-fg}",B=Y.length>q?Y.slice(0,q-1)+"…":Y.padEnd(q);Z.push(`{${z}-fg}${Q}{/${z}-fg} ${U}${B}${V} {${z}-fg}${Q}{/${z}-fg}`),Z.push(`{${z}-fg}└${"─".repeat(q+2)}┘{/${z}-fg}`),Z.push("");let G=$.amend?"[x]":"[ ]",k=$.amend?"green":"gray";if(Z.push(`{${k}-fg}${G}{/${k}-fg} Amend {gray-fg}(a){/gray-fg}`),$.error)Z.push(""),Z.push(`{red-fg}${$.error}{/red-fg}`);if($.isCommitting)Z.push(""),Z.push("{yellow-fg}Committing...{/yellow-fg}");Z.push("");let j=$.inputFocused?"Enter: commit | Esc: unfocus":"i/Enter: edit | Esc: cancel | a: toggle amend";return Z.push(`{gray-fg}Staged: ${J} file(s) | ${j}{/gray-fg}`),Z.join(`
|
|
16
|
+
`)}function m7($,J,K){if(!$)return[];let Z=$.split(`
|
|
17
|
+
`),X=[],Q=J?V7(J):null;for(let z=0;z<Z.length;z++){let q=Z[z],Y=Q?x8(q,Q):void 0;X.push({type:"code",lineNum:z+1,content:q,highlighted:Y})}if(K)X.push({type:"truncation",content:"(file truncated)"});return X}function l8($,J,K){if(!K)return $;let X=Math.max(10,J),Q=[];for(let z of $)if(z.type==="code"){let q=z.content;if(!q||q.length<=X){Q.push(z);continue}let Y=q7(q,X);for(let U=0;U<Y.length;U++){let V=Y[U];Q.push({type:"code",lineNum:V.isContinuation?0:z.lineNum,content:V.text,highlighted:void 0,isContinuation:V.isContinuation})}}else Q.push(z);return Q}function o8($,J,K){if(!K)return $.length;let X=Math.max(10,J),Q=0;for(let z of $)if(z.type==="code"){let q=z.content;if(!q||q.length<=X)Q+=1;else Q+=y7(q,X)}else Q+=1;return Q}function f7($){let J=0;for(let K of $)if(K.type==="code"&&K.lineNum>J)J=K.lineNum;return Math.max(3,String(J).length)}var r8="\x1B[0m",_$="\x1B[90m",O$="\x1B[36m",M$="\x1B[33m";function a8($,J,K,Z=0,X,Q=!1,z=!1){if(!$)return"{gray-fg}Select a file to view its contents{/gray-fg}";if(!J)return"{gray-fg}Loading...{/gray-fg}";let q=m7(J,$,Q);if(q.length===0)return"{gray-fg}(empty file){/gray-fg}";let Y=f7(q),U=K-Y-2,V=l8(q,U,z),B=X?V.slice(Z,Z+X):V.slice(Z),G=[];for(let k of B){if(k.type==="truncation"){G.push(`{escape}${M$}${k.content}${r8}{/escape}`);continue}let j=k.isContinuation??!1,O;if(j)O=">>".padStart(Y," ");else O=String(k.lineNum).padStart(Y," ");let D=k.content,H=!z&&D.length>U,A=k.highlighted&&!j,T;if(A&&k.highlighted)T=H?Y7(k.highlighted,U):k.highlighted;else{let v=D;if(H)v=v.slice(0,Math.max(0,U-1))+"...";T=v}let M=`{escape}${j?O$:_$}${O}${r8} ${T||" "}{/escape}`;G.push(M)}return G.join(`
|
|
18
|
+
`)}function s8($,J,K,Z,X){if(!$)return 0;let Q=m7($,J,K),z=f7(Q),q=Z-z-2;return o8(Q,q,X)}function n8($,J,K,Z,X,Q,z,q){if($.bottomTab==="history")return _8(K,$.historySelectedIndex,$.currentPane==="history",z,$.historyScrollOffset,q);if($.bottomTab==="compare"){let Y=Z?.commits??[],U=Z?.files??[];return E8(Y,U,X,$.currentPane==="compare",z,$.compareScrollOffset,q)}if($.bottomTab==="explorer"){let Y=Q?.displayRows??[];return I8(Y,$.explorerSelectedIndex,$.currentPane==="explorer",z,$.explorerScrollOffset,q,Q?.isLoading??!1,Q?.error??null)}return U8(J,$.selectedIndex,$.currentPane==="files",z,$.fileListScrollOffset,q)}function i8($,J,K,Z,X,Q,z,q,Y,U){if($.bottomTab==="commit")return{content:d8(Q,z,Y),totalRows:0};if($.bottomTab==="history"){let G=K?.selectedCommit??null,k=K?.commitDiff??null,{content:j,totalRows:O}=c8(G,k,Y,$.diffScrollOffset,U,q,$.wrapMode);return{content:j,totalRows:O}}if($.bottomTab==="compare"){let G=Z?.diff??null;if(G){let{content:k,totalRows:j}=g7(G,Y,$.diffScrollOffset,U,q,$.wrapMode);return{content:k,totalRows:j}}return{content:"{gray-fg}Select a commit or file to view diff{/gray-fg}",totalRows:0}}if($.bottomTab==="explorer")return{content:a8(X?.path??null,X?.content??null,Y,$.explorerFileScrollOffset,U,X?.truncated??!1,$.wrapMode),totalRows:0};let{content:V,totalRows:B}=g7(J,Y,$.diffScrollOffset,U,q,$.wrapMode);return{content:V,totalRows:B}}var B7=3;function $9($,J,K){$.topPane.on("wheeldown",()=>{t8(B7,$,K)}),$.topPane.on("wheelup",()=>{t8(-B7,$,K)}),$.bottomPane.on("wheeldown",()=>{e8(B7,$,K)}),$.bottomPane.on("wheelup",()=>{e8(-B7,$,K)}),$.topPane.on("click",(Z)=>{let X=$.screenYToTopPaneRow(Z.y);if(X>=0)H$(X,Z.x,J,K)}),$.footerBox.on("click",(Z)=>{D$(Z.x,J,K)})}function H$($,J,K,Z){let X=Z.uiState.state;if(X.bottomTab==="history"){let Q=X.historyScrollOffset+$;Z.uiState.setHistorySelectedIndex(Q),K.selectHistoryCommitByIndex(Q)}else if(X.bottomTab==="compare"){let Q=Z.getCompareCommits(),z=Z.getCompareFiles(),q=I7(X.compareScrollOffset+$,Q,z);if(q)K.selectCompareItem(q)}else if(X.bottomTab==="explorer"){let Q=X.explorerScrollOffset+$;Z.explorerManager?.selectIndex(Q),Z.uiState.setExplorerSelectedIndex(Q)}else{let Q=Z.getStatusFiles(),z=G8($+X.fileListScrollOffset,Q);if(z!==null&&z>=0)if(J!==void 0&&J>=2&&J<=4)K.toggleFileByIndex(z);else Z.uiState.setSelectedIndex(z),K.selectFileByIndex(z)}}function D$($,J,K){let Z=K.getScreenWidth(),X=[{tab:"explorer",width:11},{tab:"compare",width:10},{tab:"history",width:10},{tab:"commit",width:9},{tab:"diff",width:7}],Q=Z;for(let{tab:z,width:q}of X){let Y=Q-q-1;if($>=Y&&$<Q){K.uiState.setTab(z);return}Q=Y}if($>=2&&$<=9)J.toggleMouseMode();else if($>=11&&$<=16)K.uiState.toggleAutoTab();else if($>=18&&$<=23)K.uiState.toggleWrapMode();else if($>=25&&$<=32)J.toggleFollow();else if($>=34&&$<=43&&K.uiState.state.bottomTab==="explorer")K.explorerManager?.toggleShowOnlyChanges();else if($===0)K.uiState.openModal("hotkeys")}function t8($,J,K){let Z=K.uiState.state,X=J.dimensions.topPaneHeight;if(Z.bottomTab==="history"){let Q=K.getHistoryCommitCount(),z=Math.max(0,Q-X),q=Math.min(z,Math.max(0,Z.historyScrollOffset+$));K.uiState.setHistoryScrollOffset(q)}else if(Z.bottomTab==="compare"){let Q=L8(K.getCompareCommits(),K.getCompareFiles()),z=Math.max(0,Q-X),q=Math.min(z,Math.max(0,Z.compareScrollOffset+$));K.uiState.setCompareScrollOffset(q)}else if(Z.bottomTab==="explorer"){let Q=R8(K.explorerManager?.state.displayRows??[]),z=Math.max(0,Q-X),q=Math.min(z,Math.max(0,Z.explorerScrollOffset+$));K.uiState.setExplorerScrollOffset(q)}else{let Q=K.getStatusFiles(),z=B8(Q),q=Math.max(0,z-X),Y=Math.min(q,Math.max(0,Z.fileListScrollOffset+$));K.uiState.setFileListScrollOffset(Y)}}function e8($,J,K){let Z=K.uiState.state,X=J.dimensions.bottomPaneHeight,Q=K.getScreenWidth();if(Z.bottomTab==="explorer"){let z=K.explorerManager?.state.selectedFile,q=s8(z?.content??null,z?.path??null,z?.truncated??!1,Q,Z.wrapMode),Y=Math.max(0,q-X),U=Math.min(Y,Math.max(0,Z.explorerFileScrollOffset+$));K.uiState.setExplorerFileScrollOffset(U)}else{let z=Math.max(0,K.getBottomPaneTotalRows()-X),q=Math.min(z,Math.max(0,Z.diffScrollOffset+$));K.uiState.setDiffScrollOffset(q)}}import*as m from"node:fs";import*as j7 from"node:path";import{watch as N$}from"chokidar";import{EventEmitter as W$}from"node:events";import*as y from"node:fs";import*as r from"node:path";import*as G7 from"node:os";var v$={targetFile:r.join(G7.homedir(),".cache","diffstalker","target"),watcherEnabled:!1,debug:!1,theme:"dark"},o=r.join(G7.homedir(),".config","diffstalker","config.json"),A$=["dark","light","dark-colorblind","light-colorblind","dark-ansi","light-ansi"];function T$($){return typeof $==="string"&&A$.includes($)}function J9(){let $={...v$};if(process.env.DIFFSTALKER_PAGER)$.pager=process.env.DIFFSTALKER_PAGER;if(y.existsSync(o))try{let J=JSON.parse(y.readFileSync(o,"utf-8"));if(J.pager)$.pager=J.pager;if(J.targetFile)$.targetFile=J.targetFile;if(T$(J.theme))$.theme=J.theme;if(typeof J.splitRatio==="number"&&J.splitRatio>=0.15&&J.splitRatio<=0.85)$.splitRatio=J.splitRatio}catch{}return $}function h7($){let J=r.dirname(o);if(!y.existsSync(J))y.mkdirSync(J,{recursive:!0});let K={};if(y.existsSync(o))try{K=JSON.parse(y.readFileSync(o,"utf-8"))}catch{}Object.assign(K,$),y.writeFileSync(o,JSON.stringify(K,null,2)+`
|
|
19
|
+
`)}function K9($){let J=r.dirname($);if(!y.existsSync(J))y.mkdirSync(J,{recursive:!0})}function Z9($){let J=G7.homedir();if($.startsWith(J))return"~"+$.slice(J.length);return $}import*as X9 from"node:path";import*as c7 from"node:os";function Q9($){if($.startsWith("~/"))return X9.join(c7.homedir(),$.slice(2));if($==="~")return c7.homedir();return $}function d7($){let J=$.split(`
|
|
20
|
+
`);for(let K=J.length-1;K>=0;K--){let Z=J[K].trim();if(Z)return Z}return""}class l7 extends W${targetFile;debug;watcher=null;debounceTimer=null;lastReadPath=null;_state={path:null,lastUpdate:null,rawContent:null,sourceFile:null};constructor($,J=!1){super();this.targetFile=$,this.debug=J,this._state.sourceFile=$}get state(){return this._state}updateState($){this._state={...this._state,...$},this.emit("path-change",this._state)}processContent($){if(!$)return null;let J=Q9($);return j7.isAbsolute(J)?J:j7.resolve(J)}readTargetDebounced(){if(this.debounceTimer)clearTimeout(this.debounceTimer);this.debounceTimer=setTimeout(()=>{this.readTarget()},100)}readTarget(){try{let $=m.readFileSync(this.targetFile,"utf-8"),J=d7($);if(J&&J!==this.lastReadPath){let K=this.processContent(J),Z=new Date;if(this.debug&&K)process.stderr.write(`[diffstalker ${Z.toISOString()}] Path change detected
|
|
21
|
+
`),process.stderr.write(` Source file: ${this.targetFile}
|
|
22
|
+
`),process.stderr.write(` Raw content: "${J}"
|
|
23
|
+
`),process.stderr.write(` Previous: "${this.lastReadPath??"(none)"}"
|
|
24
|
+
`),process.stderr.write(` Resolved: "${K}"
|
|
25
|
+
`);this.lastReadPath=K,this.updateState({path:K,lastUpdate:Z,rawContent:J})}}catch{}}start(){if(K9(this.targetFile),!m.existsSync(this.targetFile))m.writeFileSync(this.targetFile,"");try{let $=m.readFileSync(this.targetFile,"utf-8"),J=d7($);if(J){let K=this.processContent(J),Z=new Date;if(this.debug&&K)process.stderr.write(`[diffstalker ${Z.toISOString()}] Initial path read
|
|
26
|
+
`),process.stderr.write(` Source file: ${this.targetFile}
|
|
27
|
+
`),process.stderr.write(` Raw content: "${J}"
|
|
28
|
+
`),process.stderr.write(` Resolved: "${K}"
|
|
29
|
+
`);this.lastReadPath=K,this._state={path:K,lastUpdate:Z,rawContent:J,sourceFile:this.targetFile}}}catch{}this.watcher=N$(this.targetFile,{persistent:!0,ignoreInitial:!0}),this.watcher.on("change",()=>this.readTargetDebounced()),this.watcher.on("add",()=>this.readTargetDebounced())}stop(){if(this.debounceTimer)clearTimeout(this.debounceTimer),this.debounceTimer=null;if(this.watcher)this.watcher.close(),this.watcher=null}}class k7{targetFile;getCurrentRepoPath;callbacks;watcher=null;_watcherState={enabled:!1};constructor($,J,K){this.targetFile=$,this.getCurrentRepoPath=J,this.callbacks=K}get watcherState(){return this._watcherState}get isEnabled(){return this.watcher!==null}start(){this.watcher=new l7(this.targetFile),this.watcher.on("path-change",(J)=>{if(J.path&&J.path!==this.getCurrentRepoPath())this._watcherState={enabled:!0,sourceFile:J.sourceFile??this.targetFile,rawContent:J.rawContent??void 0,lastUpdate:J.lastUpdate??void 0},this.callbacks.onRepoChange(J.path,this._watcherState);if(J.rawContent)this.callbacks.onFileNavigate(J.rawContent)}),this._watcherState={enabled:!0,sourceFile:this.targetFile},this.watcher.start();let $=this.watcher.state;if($.path&&$.path!==this.getCurrentRepoPath())this._watcherState={enabled:!0,sourceFile:$.sourceFile??this.targetFile,rawContent:$.rawContent??void 0,lastUpdate:$.lastUpdate??void 0},this.callbacks.onRepoChange($.path,this._watcherState);else if($.rawContent)this._watcherState.rawContent=$.rawContent,this.callbacks.onFileNavigate($.rawContent)}toggle(){if(this.watcher)this.stop();else this.start()}stop(){if(this.watcher)this.watcher.stop(),this.watcher=null,this._watcherState={enabled:!1}}}function F$($){let J=`{bold}{green-fg}${$.current}{/green-fg}{/bold}`;if($.tracking)J+=` {gray-fg}→{/gray-fg} {blue-fg}${$.tracking}{/blue-fg}`;if($.ahead>0)J+=` {green-fg}↑${$.ahead}{/green-fg}`;if($.behind>0)J+=` {red-fg}↓${$.behind}{/red-fg}`;return J}function z9($,J,K,Z,X){if(!$)return"{gray-fg}Waiting for target path...{/gray-fg}";let Q=Z9($),z=Z==="Not a git repository",q=`{bold}{cyan-fg}${Q}{/cyan-fg}{/bold}`;if(K)q+=" {yellow-fg}⟳{/yellow-fg}";if(z)q+=" {yellow-fg}(not a git repository){/yellow-fg}";else if(Z)q+=` {red-fg}(${Z}){/red-fg}`;let Y=J?F$(J):"";if(Y){let U=Q.length;if(K)U+=2;if(z)U+=24;else if(Z)U+=Z.length+3;let V=J?J.current.length+(J.tracking?3+J.tracking.length:0)+(J.ahead>0?3+String(J.ahead).length:0)+(J.behind>0?3+String(J.behind).length:0):0,B=Math.max(1,X-U-V-2);return q+" ".repeat(B)+Y}return q}function q9($){return $.replace(/\{[^}]+\}/g,"").length}function V9($,J,K,Z,X,Q,z){let q="{gray-fg}?{/gray-fg} ";if(q+=J?"{yellow-fg}[scroll]{/yellow-fg}":"{yellow-fg}m:[select]{/yellow-fg}",q+=" ",q+=K?"{blue-fg}[auto]{/blue-fg}":"{gray-fg}[auto]{/gray-fg}",q+=" ",q+=Z?"{blue-fg}[wrap]{/blue-fg}":"{gray-fg}[wrap]{/gray-fg}",q+=" ",q+=X?"{blue-fg}[follow]{/blue-fg}":"{gray-fg}[follow]{/gray-fg}",$==="explorer")q+=" ",q+=Q?"{blue-fg}[changes]{/blue-fg}":"{gray-fg}[changes]{/gray-fg}";let U=[{key:"1",label:"Diff",tab:"diff"},{key:"2",label:"Commit",tab:"commit"},{key:"3",label:"History",tab:"history"},{key:"4",label:"Compare",tab:"compare"},{key:"5",label:"Explorer",tab:"explorer"}].map(({key:k,label:j,tab:O})=>{if($===O)return`{bold}{cyan-fg}[${k}]${j}{/cyan-fg}{/bold}`;return`[${k}]${j}`}).join(" "),V=q9(q),B=q9(U),G=Math.max(1,z-V-B);return q+" ".repeat(G)+U}import*as f from"node:fs";import*as R from"node:path";import{EventEmitter as L$}from"node:events";import{simpleGit as E$}from"simple-git";async function e($,J){if(J.length===0)return new Set;let K=E$($),Z=new Set,X=100;for(let Q=0;Q<J.length;Q+=X){let z=J.slice(Q,Q+X);try{let Y=(await K.raw(["check-ignore",...z])).trim().split(`
|
|
30
|
+
`).filter((U)=>U.length>0);for(let U of Y)Z.add(U)}catch{}}return Z}var I$=1048576,R$=102400;function y$($){let J=Math.min($.length,8192);for(let K=0;K<J;K++)if($[K]===0)return!0;return!1}class o7 extends L${repoPath;options;expandedPaths=new Set;gitStatusMap={files:new Map,directories:new Set};_state={currentPath:"",tree:null,displayRows:[],selectedIndex:0,selectedFile:null,isLoading:!1,error:null};constructor($,J){super();this.repoPath=$,this.options={hideHidden:J.hideHidden??!0,hideGitignored:J.hideGitignored??!0,showOnlyChanges:J.showOnlyChanges??!1},this.expandedPaths.add("")}get state(){return this._state}updateState($){this._state={...this._state,...$},this.emit("state-change",this._state)}async setOptions($){this.options={...this.options,...$},await this.loadTree()}setGitStatus($){if(this.gitStatusMap=$,this._state.tree)this.applyGitStatusToTree(this._state.tree),this.refreshDisplayRows()}async toggleShowOnlyChanges(){this.options.showOnlyChanges=!this.options.showOnlyChanges,this.refreshDisplayRows()}get showOnlyChanges(){return this.options.showOnlyChanges}async loadTree(){this.updateState({isLoading:!0,error:null});try{let $=await this.buildTreeNode("",0);if($){$.expanded=!0,this.applyGitStatusToTree($);let J=this.flattenTree($);this.updateState({tree:$,displayRows:J,selectedIndex:0,selectedFile:null,isLoading:!1})}else this.updateState({tree:null,displayRows:[],isLoading:!1,error:"Failed to load directory"})}catch($){this.updateState({error:$ instanceof Error?$.message:"Failed to read directory",tree:null,displayRows:[],isLoading:!1})}}async buildTreeNode($,J){try{let K=R.join(this.repoPath,$);if(!(await f.promises.stat(K)).isDirectory())return{name:R.basename($)||this.getRepoName(),path:$,isDirectory:!1,expanded:!1,children:[],childrenLoaded:!0};let X=this.expandedPaths.has($),Q={name:R.basename($)||this.getRepoName(),path:$,isDirectory:!0,expanded:X,children:[],childrenLoaded:!1};if($===""||X)await this.loadChildrenForNode(Q);return Q}catch(K){return null}}async loadChildrenForNode($){if($.childrenLoaded)return;try{let J=R.join(this.repoPath,$.path),K=await f.promises.readdir(J,{withFileTypes:!0}),Z=K.map((z)=>$.path?R.join($.path,z.name):z.name),X=this.options.hideGitignored?await e(this.repoPath,Z):new Set,Q=[];for(let z of K){if(this.options.hideHidden&&z.name.startsWith("."))continue;let q=$.path?R.join($.path,z.name):z.name;if(this.options.hideGitignored&&X.has(q))continue;let Y=z.isDirectory(),U=this.expandedPaths.has(q),V={name:z.name,path:q,isDirectory:Y,expanded:U,children:[],childrenLoaded:!Y};if(Y&&U)await this.loadChildrenForNode(V);Q.push(V)}Q.sort((z,q)=>{if(z.isDirectory&&!q.isDirectory)return-1;if(!z.isDirectory&&q.isDirectory)return 1;return z.name.localeCompare(q.name)}),this.collapseNode($,Q),$.childrenLoaded=!0}catch(J){$.childrenLoaded=!0,$.children=[]}}collapseNode($,J){for(let K of J)if(K.isDirectory&&K.childrenLoaded)while(K.children.length===1&&K.children[0].isDirectory&&K.children[0].childrenLoaded){let Z=K.children[0];K.name=`${K.name}/${Z.name}`,K.path=Z.path,K.children=Z.children,K.expanded=this.expandedPaths.has(K.path)}$.children=J}applyGitStatusToTree($){if(!$.isDirectory){let J=this.gitStatusMap.files.get($.path);if(J)$.gitStatus=J.status;else $.gitStatus=void 0}else{$.hasChangedChildren=this.gitStatusMap.directories.has($.path);for(let J of $.children)this.applyGitStatusToTree(J)}}flattenTree($){let J=[],K=(Z,X,Q)=>{if(X===0){for(let z=0;z<Z.children.length;z++){let q=Z.children[z],Y=z===Z.children.length-1;if(this.options.showOnlyChanges){if(q.isDirectory&&!q.hasChangedChildren)continue;if(!q.isDirectory&&!q.gitStatus)continue}if(J.push({node:q,depth:0,isLast:Y,parentIsLast:[]}),q.isDirectory&&q.expanded)K(q,1,[Y])}return}for(let z=0;z<Z.children.length;z++){let q=Z.children[z],Y=z===Z.children.length-1;if(this.options.showOnlyChanges){if(q.isDirectory&&!q.hasChangedChildren)continue;if(!q.isDirectory&&!q.gitStatus)continue}if(J.push({node:q,depth:X,isLast:Y,parentIsLast:[...Q]}),q.isDirectory&&q.expanded)K(q,X+1,[...Q,Y])}};return K($,0,[]),J}refreshDisplayRows(){if(!this._state.tree)return;let $=this._state.displayRows[this._state.selectedIndex]?.node.path??null,J=this.flattenTree(this._state.tree),K=0;if($!==null){let Z=J.findIndex((X)=>X.node.path===$);if(Z>=0)K=Z}K=Math.min(K,Math.max(0,J.length-1)),this.updateState({displayRows:J,selectedIndex:K})}getRepoName(){return R.basename(this.repoPath)||"repo"}async loadDirectory($){this._state.currentPath=$,await this.loadTree()}async loadFile($){try{let J=R.join(this.repoPath,$),K=await f.promises.stat(J);if(K.size>I$){this.updateState({selectedFile:{path:$,content:`File too large to display (${(K.size/1024/1024).toFixed(2)} MB).
|
|
31
|
+
Maximum size: 1 MB`,truncated:!0}});return}let Z=await f.promises.readFile(J);if(y$(Z)){this.updateState({selectedFile:{path:$,content:"Binary file - cannot display"}});return}let X=Z.toString("utf-8"),Q=!1;if(K.size>R$)X=`Warning: Large file (${(K.size/1024).toFixed(1)} KB)
|
|
37
32
|
|
|
38
|
-
`+
|
|
39
|
-
`);if(
|
|
33
|
+
`+X;let z=5000,q=X.split(`
|
|
34
|
+
`);if(q.length>z)X=q.slice(0,z).join(`
|
|
40
35
|
`)+`
|
|
41
36
|
|
|
42
|
-
... (truncated, ${y.length-v} more lines)`,_=!0;O({path:C.path,content:f,truncated:_}),Q(0)}catch(w){O({path:C.path,content:w instanceof Error?`Error: ${w.message}`:"Failed to read file"})}})()},[X,N,E,Y,Q]);let L=HJ(()=>N.length,[N]),R=WX(()=>{U((C)=>{let b=Math.max(0,C-1);if(b<J)Z(b);return b})},[J,Z]),S=WX(()=>{U((C)=>{let b=Math.min(N.length-1,C+1),w=$-1,p=N.length>w?w-2:w,f=J+p;if(b>=f)Z(J+1);return b})},[N.length,J,$,Z]),P=WX(()=>{let C=N[E];if(!C)return;if(C.isDirectory)if(C.name==="..")z(D0.dirname(q)||"");else z(C.path)},[N,E,q]),W=WX(()=>{if(q)z(D0.dirname(q)||"")},[q]);return{currentPath:q,items:N,selectedIndex:E,setSelectedIndex:U,selectedFile:M,fileScrollOffset:K,setFileScrollOffset:Q,navigateUp:R,navigateDown:S,enterDirectory:P,goUp:W,isLoading:F,error:H,explorerTotalRows:L}}import{jsx as r,jsxs as K8}from"react/jsx-runtime";import{useState as yJ}from"react";import{Box as f0,Text as Y0,useInput as PJ}from"ink";import{jsx as P9,jsxs as vJ}from"react/jsx-runtime";import{Box as T9,Text as jJ}from"ink";function Z8({x:X,y:Y,width:$,height:J,children:Z}){let K=" ".repeat($);return vJ(T9,{position:"absolute",marginLeft:X,marginTop:Y,flexDirection:"column",children:[Array.from({length:J}).map((Q,V)=>P9(jJ,{children:K},`blank-${V}`)),P9(T9,{position:"absolute",flexDirection:"column",children:Z})]})}function D8(X,Y,$,J){return{x:Math.floor(($-X)/2),y:Math.floor((J-Y)/2)}}function TJ({theme:X}){let{colors:Y}=X;return K8(f0,{flexDirection:"column",marginLeft:2,children:[K8(f0,{children:[r(Y0,{backgroundColor:Y.delBg,color:Y.delLineNum,children:" 5 "}),r(Y0,{backgroundColor:Y.delBg,color:Y.delSymbol,bold:!0,children:"- "}),r(Y0,{backgroundColor:Y.delBg,color:Y.text,children:"const "}),r(Y0,{backgroundColor:Y.delHighlight,color:Y.text,children:"old"}),r(Y0,{backgroundColor:Y.delBg,color:Y.text,children:" = value;"})]}),K8(f0,{children:[r(Y0,{backgroundColor:Y.addBg,color:Y.addLineNum,children:" 5 "}),r(Y0,{backgroundColor:Y.addBg,color:Y.addSymbol,bold:!0,children:"+ "}),r(Y0,{backgroundColor:Y.addBg,color:Y.text,children:"const "}),r(Y0,{backgroundColor:Y.addHighlight,color:Y.text,children:"new"}),r(Y0,{backgroundColor:Y.addBg,color:Y.text,children:" = value;"})]})]})}function C9({currentTheme:X,onSelect:Y,onCancel:$,width:J,height:Z}){let[K,Q]=yJ(()=>{let A=e0.indexOf(X);return A>=0?A:0}),V=UX(e0[K]);PJ((A,E)=>{if(E.escape)$();else if(E.return)Y(e0[K]);else if(E.upArrow||A==="k")Q((U)=>Math.max(0,U-1));else if(E.downArrow||A==="j")Q((U)=>Math.min(e0.length-1,U+1))});let G=Math.min(50,J-4),q=Math.min(e0.length+10,Z-4),{x:z,y:N}=D8(G,q,J,Z);return r(Z8,{x:z,y:N,width:G,height:q,children:K8(f0,{borderStyle:"round",borderColor:"cyan",flexDirection:"column",width:G,children:[r(f0,{justifyContent:"center",marginBottom:1,children:K8(Y0,{bold:!0,color:"cyan",children:[" ","Select Theme"," "]})}),e0.map((A,E)=>{let U=VX[A],M=E===K,O=A===X;return K8(f0,{children:[r(Y0,{color:M?"cyan":void 0,children:M?"▸ ":" "}),r(Y0,{bold:M,color:M?"cyan":void 0,children:U.displayName}),O&&r(Y0,{dimColor:!0,children:" (current)"})]},A)}),K8(f0,{marginTop:1,flexDirection:"column",children:[r(Y0,{dimColor:!0,children:"Preview:"}),r(TJ,{theme:V})]}),r(f0,{marginTop:1,justifyContent:"center",children:r(Y0,{dimColor:!0,children:"↑↓ navigate • Enter select • Esc cancel"})})]})})}import{jsx as J0,jsxs as Q8}from"react/jsx-runtime";import{Box as G0,Text as q8,useInput as CJ}from"ink";var d0=[{title:"Navigation",entries:[{key:"↑/k",description:"Move up"},{key:"↓/j",description:"Move down"},{key:"Tab",description:"Toggle pane focus"}]},{title:"Staging",entries:[{key:"^S",description:"Stage file"},{key:"^U",description:"Unstage file"},{key:"^A",description:"Stage all"},{key:"^Z",description:"Unstage all"},{key:"Space/Enter",description:"Toggle stage"}]},{title:"Actions",entries:[{key:"c",description:"Open commit panel"},{key:"r",description:"Refresh"},{key:"q",description:"Quit"}]},{title:"Pane Resize",entries:[{key:"[",description:"Shrink top pane"},{key:"]",description:"Grow top pane"}]},{title:"Tabs",entries:[{key:"1",description:"Diff view"},{key:"2",description:"Commit panel"},{key:"3",description:"History view"},{key:"4",description:"Compare view"},{key:"5",description:"Explorer view"},{key:"a",description:"Toggle auto-tab mode"}]},{title:"Explorer",entries:[{key:".",description:"Toggle middle-dots"},{key:"^H",description:"Toggle hidden files"},{key:"^G",description:"Toggle gitignored"},{key:"Enter",description:"Enter directory"},{key:"Backspace/h",description:"Go up"}]},{title:"Other",entries:[{key:"m",description:"Toggle scroll/select"},{key:"f",description:"Toggle follow mode"},{key:"w",description:"Toggle wrap mode"},{key:"t",description:"Theme picker"},{key:"b",description:"Base branch picker"},{key:"u",description:"Toggle uncommitted"},{key:"?",description:"This help"}]}];function S9({onClose:X,width:Y,height:$}){CJ((z,N)=>{if(N.escape||N.return||z==="?")X()});let J=Y>=90,Z=J?38:30,K=J?Math.min(82,Y-4):Math.min(40,Y-4),Q;if(J){let z=Math.ceil(d0.length/2),N=d0.slice(0,z),A=d0.slice(z),E=N.reduce((M,O)=>M+O.entries.length+2,0),U=A.reduce((M,O)=>M+O.entries.length+2,0);Q=Math.min(Math.max(E,U)+5,$-4)}else{let z=d0.reduce((N,A)=>N+A.entries.length+2,0)+4;Q=Math.min(z,$-4)}let{x:V,y:G}=D8(K,Q,Y,$),q=(z,N)=>Q8(G0,{flexDirection:"column",marginBottom:1,children:[J0(q8,{bold:!0,dimColor:!0,children:z.title}),z.entries.map((A)=>Q8(G0,{children:[J0(G0,{width:13,children:J0(q8,{color:"cyan",children:A.key})}),J0(G0,{width:N-13,children:J0(q8,{children:A.description})})]},A.key))]},z.title);if(J){let z=Math.ceil(d0.length/2),N=d0.slice(0,z),A=d0.slice(z);return J0(Z8,{x:V,y:G,width:K,height:Q,children:Q8(G0,{borderStyle:"round",borderColor:"cyan",flexDirection:"column",width:K,children:[J0(G0,{justifyContent:"center",marginBottom:1,children:Q8(q8,{bold:!0,color:"cyan",children:[" ","Keyboard Shortcuts"," "]})}),Q8(G0,{children:[J0(G0,{flexDirection:"column",width:Z,marginRight:2,children:N.map((E)=>q(E,Z))}),J0(G0,{flexDirection:"column",width:Z,children:A.map((E)=>q(E,Z))})]}),J0(G0,{marginTop:1,justifyContent:"center",children:J0(q8,{dimColor:!0,children:"Press Esc, Enter, or ? to close"})})]})})}return J0(Z8,{x:V,y:G,width:K,height:Q,children:Q8(G0,{borderStyle:"round",borderColor:"cyan",flexDirection:"column",width:K,children:[J0(G0,{justifyContent:"center",marginBottom:1,children:Q8(q8,{bold:!0,color:"cyan",children:[" ","Keyboard Shortcuts"," "]})}),d0.map((z)=>q(z,Z)),J0(G0,{marginTop:1,justifyContent:"center",children:J0(q8,{dimColor:!0,children:"Press Esc, Enter, or ? to close"})})]})})}import{jsxs as _8,jsx as Z0}from"react/jsx-runtime";import{useState as b9,useMemo as SJ}from"react";import{Box as c0,Text as N0,useInput as bJ}from"ink";function w9({candidates:X,currentBranch:Y,onSelect:$,onCancel:J,width:Z,height:K}){let[Q,V]=b9(""),[G,q]=b9(0),z=SJ(()=>{if(!Q)return X;let H=Q.toLowerCase();return X.filter((B)=>B.toLowerCase().includes(H))},[X,Q]),N=Math.min(G,Math.max(0,z.length-1));bJ((H,B)=>{if(B.escape)J();else if(B.return){if(z.length===0&&Q)$(Q);else if(z.length>0)$(z[N])}else if(B.upArrow)q((L)=>Math.max(0,L-1));else if(B.downArrow)q((L)=>Math.min(z.length-1,L+1));else if(B.backspace||B.delete)V((L)=>L.slice(0,-1)),q(0);else if(H&&!B.ctrl&&!B.meta)V((L)=>L+H),q(0)});let A=Math.min(60,Z-4),E=Math.min(10,K-10),U=Math.min(E+9,K-4),{x:M,y:O}=D8(A,U,Z,K),F=Math.max(0,N-E+1),k=z.slice(F,F+E);return Z0(Z8,{x:M,y:O,width:A,height:U,children:_8(c0,{borderStyle:"round",borderColor:"cyan",flexDirection:"column",width:A,children:[Z0(c0,{justifyContent:"center",marginBottom:1,children:_8(N0,{bold:!0,color:"cyan",children:[" ","Select Base Branch"," "]})}),_8(c0,{marginBottom:1,children:[Z0(N0,{dimColor:!0,children:"Filter: "}),Z0(N0,{color:"cyan",children:Q}),Z0(N0,{color:"cyan",children:"▌"})]}),Z0(c0,{flexDirection:"column",height:E,children:k.length>0?k.map((H,B)=>{let R=F+B===N,S=H===Y;return _8(c0,{children:[Z0(N0,{color:R?"cyan":void 0,children:R?"▸ ":" "}),Z0(N0,{bold:R,color:R?"cyan":void 0,children:H}),S&&Z0(N0,{dimColor:!0,children:" (current)"})]},H)}):Q?_8(c0,{children:[Z0(N0,{dimColor:!0,children:" No matches. Press Enter to use: "}),Z0(N0,{color:"yellow",children:Q})]}):Z0(N0,{dimColor:!0,children:" No candidates found"})}),z.length>E&&Z0(c0,{children:_8(N0,{dimColor:!0,children:[F>0?"↑ ":" ",F+E<z.length?"↓ more":""]})}),Z0(c0,{marginTop:1,justifyContent:"center",children:Z0(N0,{dimColor:!0,children:"↑↓ navigate • Enter select • Esc cancel"})})]})})}function g9({config:X,initialPath:Y}){let{exit:$}=wJ(),{rows:J,columns:Z}=V9(),{state:K,setEnabled:Q}=T4(X.watcherEnabled,X.targetFile,X.debug),V=Y??K.path??process.cwd(),{status:G,diff:q,selectedFile:z,isLoading:N,error:A,selectFile:E,stage:U,unstage:M,discard:O,stageAll:F,unstageAll:k,commit:H,refresh:B,getHeadCommitMessage:L,compareDiff:R,compareLoading:S,compareError:P,refreshCompareDiff:W,getCandidateBaseBranches:C,setCompareBaseBranch:b,historySelectedCommit:w,historyCommitDiff:g,selectHistoryCommit:p,compareSelectionDiff:f,selectCompareCommit:_}=K9(V),v=G?.files??[],y=oY(v),T=v.filter((I)=>I.staged).length,[j,x]=Q0("files"),[D,y8]=Q0("diff"),[l0,s8]=Q0(0),[P8,DX]=Q0(null),[UY,x9]=Q0(!1),[GY,p9]=Q0(X.theme),[T8,n0]=Q0(null),[_X,NY]=Q0(!1),[_0,AY]=Q0(!1),[a8,vX]=Q0(0),[BY,jX]=Q0(0),[EY,u9]=Q0(!1),[MY,h9]=Q0(!0),[LY,m9]=Q0(!0),OY=lY(V,G?.branch??null,K,Z,A,N),f9=OY-1,{topPaneHeight:r0,bottomPaneHeight:yX,paneBoundaries:kY,splitRatio:PX,adjustSplitRatio:WY,fileListScrollOffset:TX,diffScrollOffset:d9,historyScrollOffset:i8,compareScrollOffset:t8,setDiffScrollOffset:b0,setHistoryScrollOffset:CX,setCompareScrollOffset:c9,scrollDiff:z8,scrollFileList:HY,scrollHistory:IY,scrollCompare:FY}=W9(J,Z,v,l0,q,D,void 0,X.splitRatio,f9),V8=VY(()=>{let I=X8(q);if(!_0)return I.length;let W0=R0(I),H0=Z-W0-5;return L8(I,H0,!0)},[q,_0,Z]),{commits:C8,historySelectedIndex:l9,setHistorySelectedIndex:S8,historyDiffTotalRows:RY,navigateHistoryUp:DY,navigateHistoryDown:_Y,historyTotalRows:vY}=D9({repoPath:V,isActive:D==="history",selectHistoryCommit:p,historyCommitDiff:g,historySelectedCommit:w,topPaneHeight:r0,historyScrollOffset:i8,setHistoryScrollOffset:CX,setDiffScrollOffset:b0,status:G,wrapMode:_0,terminalWidth:Z}),{includeUncommitted:n9,compareListSelection:w0,baseBranchCandidates:r9,showBaseBranchPicker:SX,compareTotalItems:e8,compareDiffTotalRows:U8,setCompareSelectedIndex:jY,toggleIncludeUncommitted:o9,openBaseBranchPicker:s9,closeBaseBranchPicker:a9,selectBaseBranch:i9,navigateCompareUp:yY,navigateCompareDown:PY,markSelectionInitialized:TY,getItemIndexFromRow:CY}=v9({repoPath:V,isActive:D==="compare",compareDiff:R,refreshCompareDiff:W,getCandidateBaseBranches:C,setCompareBaseBranch:b,selectCompareCommit:_,topPaneHeight:r0,compareScrollOffset:t8,setCompareScrollOffset:c9,setDiffScrollOffset:b0,status:G,wrapMode:_0,terminalWidth:Z}),{currentPath:t9,items:XX,selectedIndex:e9,setSelectedIndex:SY,selectedFile:G8,navigateUp:bY,navigateDown:wY,enterDirectory:X$,goUp:Y$,isLoading:$$,error:J$,explorerTotalRows:gY}=y9({repoPath:V,isActive:D==="explorer",topPaneHeight:r0,explorerScrollOffset:a8,setExplorerScrollOffset:vX,fileScrollOffset:BY,setFileScrollOffset:jX,hideHiddenFiles:MY,hideGitignored:LY}),xY=VY(()=>{if(!G8)return 0;return F4(G8.content,G8.path,G8.truncated??!1,Z,_0)},[G8,Z,_0]),pY=FX(kY);pY.current=kY;let Z$=FX(X.splitRatio);v8(()=>{if(PX!==Z$.current){let I=setTimeout(()=>pX({splitRatio:PX}),500);return()=>clearTimeout(I)}},[PX]);let K0=VY(()=>hX(v,l0),[v,l0]);v8(()=>{if(y>0&&l0>=y)s8(Math.max(0,y-1))},[y,l0]),v8(()=>{E(K0)},[K0,E]),v8(()=>{if(D==="diff"||D==="commit")b0(0)},[l0,D,b0]),v8(()=>{b0(0)},[_0,b0]);let o0=k0((I)=>{y8(I),x({diff:"files",commit:"commit",history:"history",compare:"compare",explorer:"explorer"}[I])},[]),uY=FX(()=>{}),K$=k0((I)=>{let{x:W0,y:H0,type:YX,button:gX}=I,{stagingPaneStart:N8,fileListEnd:xX,diffPaneStart:L$,diffPaneEnd:O$,footerRow:k$}=pY.current;if(YX==="click"){if(T8!==null){n0(null);return}if(H0===k$&&gX==="left"){let A0=E9(W0,Z);if(A0){o0(A0);return}let i=L9(W0);if(i==="hotkeys"){n0("hotkeys");return}else if(i==="mouse-mode"){uY.current();return}else if(i==="auto-tab"){NY((d)=>!d);return}else if(i==="wrap"){AY((d)=>!d);return}}if(OX(H0,N8+1,xX)){let A0=r0-1,i=(d)=>d>A0?1:0;if(D==="diff"||D==="commit"){let d=B9(H0,TX,v,N8,xX);if(d>=0&&d<y){s8(d),x("files");let l=hX(v,d);if(l){if(gX==="right"&&!l.staged&&l.status!=="untracked")DX(l);else if(gX==="left"&&M9(W0))if(l.staged)M(l);else U(l)}return}}else if(D==="history"){let d=i(C8.length),l=H0-N8-1-d,s0=cX(l,C8,Z,i8);if(s0>=0&&s0<C8.length){S8(s0),x("history"),b0(0);return}}else if(D==="compare"&&R){let d=i(e8),l=H0-N8-1-d+t8,s0=CY(l);if(s0>=0&&s0<e8){TY(),jY(s0),x("compare");return}}else if(D==="explorer"){let d=i(XX.length),l=H0-N8-1-d+a8;if(l>=0&&l<XX.length){SY(l),x("explorer");return}}}if(OX(H0,L$,O$))x(D)}else if(YX==="scroll-up"||YX==="scroll-down"){let A0=YX==="scroll-up"?"up":"down";if(OX(H0,N8,xX)){if(D==="diff"||D==="commit")HY(A0);else if(D==="history")IY(A0,vY);else if(D==="compare")FY(A0,e8);else if(D==="explorer"){let i=A0==="up"?-3:3,d=E8(gY,r0-1);vX((l)=>Math.max(0,Math.min(l+i,d)))}}else if(D==="explorer"){let i=A0==="up"?-3:3,d=E8(xY,yX-1);jX((l)=>Math.max(0,Math.min(l+i,d)))}else{let i;if(D==="compare"&&w0?.type!=="commit")i=U8;else if(D==="history")i=RY;else if(D==="diff")i=V8;z8(A0,3,i)}}},[Z,TX,v,y,D,C8,R,e8,U,M,z8,HY,IY,FY,i8,t8,b0,S8,jY,TY,CY,w0?.type,U8,V8,RY,vY,T8,XX,a8,gY,xY,r0,yX,SY,vX,jX]),Q$=UY||SX,{mouseEnabled:q$,toggleMouse:hY}=z9(K$,Q$);uY.current=hY;let bX=FX(y);v8(()=>{if(!_X){bX.current=y;return}let I=bX.current;if(I===0&&y>0)o0("diff");else if(I>0&&y===0)S8(0),CX(0),o0("history");bX.current=y},[y,_X,o0,S8,CX]);let z$=k0(()=>{if(j==="files")s8((I)=>Math.max(0,I-1));else if(j==="diff"){let I;if(D==="compare"&&w0?.type!=="commit")I=U8;else if(D==="diff")I=V8;z8("up",3,I)}else if(j==="history")DY();else if(j==="compare")yY();else if(j==="explorer")bY()},[j,D,w0?.type,U8,V8,z8,DY,yY,bY]),V$=k0(()=>{if(j==="files")s8((I)=>Math.min(y-1,I+1));else if(j==="diff"){let I;if(D==="compare"&&w0?.type!=="commit")I=U8;else if(D==="diff")I=V8;z8("down",3,I)}else if(j==="history")_Y();else if(j==="compare")PY();else if(j==="explorer")wY()},[j,D,w0?.type,U8,V8,y,z8,_Y,PY,wY]),U$=k0(()=>{if(D==="diff"||D==="commit")x((I)=>I==="files"?"diff":"files");else if(D==="history")x((I)=>I==="history"?"diff":"history");else if(D==="compare")x((I)=>I==="compare"?"diff":"compare");else if(D==="explorer")x((I)=>I==="explorer"?"diff":"explorer")},[D]),G$=k0(async()=>{if(K0&&!K0.staged)await U(K0)},[K0,U]),N$=k0(async()=>{if(K0?.staged)await M(K0)},[K0,M]),A$=k0(async()=>{if(!K0)return;if(K0.staged)await M(K0);else await U(K0)},[K0,U,M]),B$=k0(()=>o0("commit"),[o0]),E$=k0(()=>{y8("diff"),x("files")},[]),M$=k0((I)=>{p9(I),n0(null),pX({theme:I})},[]);Q9({onStage:G$,onUnstage:N$,onStageAll:F,onUnstageAll:k,onCommit:B$,onQuit:$,onRefresh:B,onNavigateUp:z$,onNavigateDown:V$,onTogglePane:U$,onSwitchTab:o0,onSelect:A$,onToggleIncludeUncommitted:o9,onCycleBaseBranch:s9,onOpenThemePicker:()=>n0("theme"),onShrinkTopPane:()=>WY(-zY),onGrowTopPane:()=>WY(zY),onOpenHotkeysModal:()=>n0("hotkeys"),onToggleMouse:hY,onToggleFollow:()=>Q((I)=>!I),onToggleAutoTab:()=>NY((I)=>!I),onToggleWrap:()=>AY((I)=>!I),onToggleMiddleDots:D==="explorer"?()=>u9((I)=>!I):void 0,onToggleHideHiddenFiles:D==="explorer"?()=>h9((I)=>!I):void 0,onToggleHideGitignored:D==="explorer"?()=>m9((I)=>!I):void 0,onExplorerEnter:D==="explorer"?X$:void 0,onExplorerBack:D==="explorer"?Y$:void 0},j,UY||T8!==null||SX),gJ((I,W0)=>{if(!P8)return;if(I==="y"||I==="Y")O(P8),DX(null);else if(I==="n"||I==="N"||W0.escape)DX(null)},{isActive:!!P8});let wX=()=>X0(n8,{dimColor:!0,children:"─".repeat(Z)});return IX(j8,{flexDirection:"column",height:J,width:Z,overflowX:"hidden",children:[X0(j8,{height:OY,width:Z,children:X0(nY,{repoPath:V,branch:G?.branch??null,isLoading:N,error:A,debug:X.debug,watcherState:K,width:Z})}),X0(wX,{}),X0(J4,{bottomTab:D,currentPane:j,terminalWidth:Z,topPaneHeight:r0,files:v,selectedIndex:l0,fileListScrollOffset:TX,stagedCount:T,onStage:U,onUnstage:M,commits:C8,historySelectedIndex:l9,historyScrollOffset:i8,onSelectHistoryCommit:(I,W0)=>S8(W0),compareDiff:R,compareListSelection:w0,compareScrollOffset:t8,includeUncommitted:n9,explorerCurrentPath:t9,explorerItems:XX,explorerSelectedIndex:e9,explorerScrollOffset:a8,explorerIsLoading:$$,explorerError:J$,hideHiddenFiles:MY,hideGitignored:LY}),X0(wX,{}),X0(D4,{bottomTab:D,currentPane:j,terminalWidth:Z,bottomPaneHeight:yX,diffScrollOffset:d9,currentTheme:GY,diff:q,selectedFile:z,stagedCount:T,onCommit:H,onCommitCancel:E$,getHeadCommitMessage:L,onCommitInputFocusChange:x9,historySelectedCommit:w,historyCommitDiff:g,compareDiff:R,compareLoading:S,compareError:P,compareListSelection:w0,compareSelectionDiff:f,wrapMode:_0,explorerSelectedFile:G8,explorerFileScrollOffset:BY,showMiddleDots:EY}),X0(wX,{}),P8?IX(j8,{children:[IX(n8,{color:"yellow",bold:!0,children:["Discard changes to"," "]}),X0(n8,{color:"cyan",children:P8.path}),IX(n8,{color:"yellow",bold:!0,children:["?"," "]}),X0(n8,{dimColor:!0,children:"(y/n)"})]}):X0(eY,{activeTab:D,mouseEnabled:q$,autoTabEnabled:_X,wrapMode:_0,showMiddleDots:EY}),T8==="theme"&&X0(j8,{position:"absolute",marginTop:0,marginLeft:0,children:X0(C9,{currentTheme:GY,onSelect:M$,onCancel:()=>n0(null),width:Z,height:J})}),T8==="hotkeys"&&X0(j8,{position:"absolute",marginTop:0,marginLeft:0,children:X0(S9,{onClose:()=>n0(null),width:Z,height:J})}),SX&&X0(j8,{position:"absolute",marginTop:0,marginLeft:0,children:X0(w9,{candidates:r9,currentBranch:R?.baseBranch??null,onSelect:i9,onCancel:a9,width:Z,height:J})})]})}function o8(){process.stdout.write("\x1B[?1006l"),process.stdout.write("\x1B[?1002l"),process.stdout.write("\x1B[?1000l"),process.stdout.write("\x1B[?25h")}process.on("exit",o8);process.on("SIGINT",()=>{o8(),process.exit(0)});process.on("SIGTERM",()=>{o8(),process.exit(0)});process.on("uncaughtException",(X)=>{o8(),console.error("Uncaught exception:",X),process.exit(1)});process.on("unhandledRejection",(X)=>{o8(),console.error("Unhandled rejection:",X),process.exit(1)});function uJ(X){let Y={};for(let $=0;$<X.length;$++){let J=X[$];if(J==="--follow"||J==="-f"){if(Y.follow=!0,X[$+1]&&!X[$+1].startsWith("-"))Y.followFile=X[++$]}else if(J==="--once")Y.once=!0;else if(J==="--debug"||J==="-d")Y.debug=!0;else if(J==="--help"||J==="-h")console.log(`
|
|
37
|
+
... (truncated, ${q.length-z} more lines)`,Q=!0;this.updateState({selectedFile:{path:$,content:X,truncated:Q}})}catch(J){this.updateState({selectedFile:{path:$,content:J instanceof Error?`Error: ${J.message}`:"Failed to read file"}})}}async selectIndex($){let J=this._state.displayRows;if($<0||$>=J.length)return;let K=J[$];if(this.updateState({selectedIndex:$}),K&&!K.node.isDirectory)await this.loadFile(K.node.path);else this.updateState({selectedFile:null})}navigateUp($){let J=Math.max(0,this._state.selectedIndex-1);if(J===this._state.selectedIndex)return null;if(this.selectIndex(J),J<$)return J;return null}navigateDown($,J){let K=Math.min(this._state.displayRows.length-1,this._state.selectedIndex+1);if(K===this._state.selectedIndex)return null;this.selectIndex(K);let X=this._state.displayRows.length>J?J-2:J,Q=$+X;if(K>=Q)return $+1;return null}async toggleExpand(){let $=this._state.displayRows,J=this._state.selectedIndex;if(J<0||J>=$.length)return;let K=$[J];if(!K.node.isDirectory)return;let Z=K.node;if(Z.expanded)this.expandedPaths.delete(Z.path),Z.expanded=!1;else if(this.expandedPaths.add(Z.path),Z.expanded=!0,!Z.childrenLoaded)await this.loadChildrenForNode(Z),this.applyGitStatusToTree(Z);this.refreshDisplayRows()}async enterDirectory(){let $=this._state.displayRows,J=this._state.selectedIndex;if(J<0||J>=$.length)return;if($[J].node.isDirectory)await this.toggleExpand()}async goUp(){let $=this._state.displayRows,J=this._state.selectedIndex;if(J<0||J>=$.length)return;let Z=$[J].node.path,X=R.dirname(Z);if(X==="."||X==="")return;let Q=Z.split("/");for(let z=Q.length-1;z>0;z--){let q=Q.slice(0,z).join("/");if(this.expandedPaths.has(q)){this.expandedPaths.delete(q);let Y=this.findNodeByPath(q);if(Y)Y.expanded=!1;this.refreshDisplayRows();let V=this._state.displayRows.findIndex((B)=>B.node.path===q);if(V>=0)this.updateState({selectedIndex:V,selectedFile:null});return}}}findNodeByPath($){if(!this._state.tree)return null;let J=(K)=>{if(K.path===$)return K;for(let Z of K.children){let X=J(Z);if(X)return X}return null};return J(this._state.tree)}async getAllFilePaths(){let $=[],J=async(K)=>{try{let Z=R.join(this.repoPath,K),X=await f.promises.readdir(Z,{withFileTypes:!0}),Q=X.map((q)=>K?R.join(K,q.name):q.name),z=this.options.hideGitignored?await e(this.repoPath,Q):new Set;for(let q of X){if(this.options.hideHidden&&q.name.startsWith("."))continue;let Y=K?R.join(K,q.name):q.name;if(this.options.hideGitignored&&z.has(Y))continue;if(q.isDirectory())await J(Y);else $.push(Y)}}catch(Z){}};return await J(""),$}async navigateToPath($){if(!this._state.tree)return!1;let J=$.split("/"),K="";for(let X=0;X<J.length-1;X++)K=K?`${K}/${J[X]}`:J[X],this.expandedPaths.add(K);await this.loadTree();let Z=this._state.displayRows.findIndex((X)=>X.node.path===$);if(Z>=0)return await this.selectIndex(Z),!0;return!1}dispose(){this.removeAllListeners()}}import C$ from"neo-blessed";class r7{box;screen;selectedIndex;currentTheme;onSelect;onCancel;constructor($,J,K,Z){if(this.screen=$,this.currentTheme=J,this.onSelect=K,this.onCancel=Z,this.selectedIndex=x.indexOf(J),this.selectedIndex<0)this.selectedIndex=0;let X=50,Q=x.length+12;this.box=C$.box({parent:$,top:"center",left:"center",width:X,height:Q,border:{type:"line"},style:{border:{fg:"cyan"}},tags:!0,keys:!0}),this.setupKeyHandlers(),this.render()}setupKeyHandlers(){this.box.key(["escape","q"],()=>{this.close(),this.onCancel()}),this.box.key(["enter","space"],()=>{let $=x[this.selectedIndex];this.close(),this.onSelect($)}),this.box.key(["up","k"],()=>{this.selectedIndex=Math.max(0,this.selectedIndex-1),this.render()}),this.box.key(["down","j"],()=>{this.selectedIndex=Math.min(x.length-1,this.selectedIndex+1),this.render()})}render(){let $=[];$.push("{bold}{cyan-fg} Select Theme{/cyan-fg}{/bold}"),$.push("");for(let K=0;K<x.length;K++){let Z=x[K],X=z7[Z],Q=K===this.selectedIndex,z=Z===this.currentTheme,q=Q?"{cyan-fg}{bold}> ":" ";if(q+=X.displayName,Q)q+="{/bold}{/cyan-fg}";if(z)q+=" {gray-fg}(current){/gray-fg}";$.push(q)}$.push(""),$.push("{gray-fg}Preview:{/gray-fg}");let J=t(x[this.selectedIndex]);$.push(" {green-fg}+ added line{/green-fg}"),$.push(" {red-fg}- deleted line{/red-fg}"),$.push(""),$.push("{gray-fg}j/k: navigate | Enter: select | Esc: cancel{/gray-fg}"),this.box.setContent($.join(`
|
|
38
|
+
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import P$ from"neo-blessed";var u=[{title:"Navigation",entries:[{key:"j/k",description:"Move up/down"},{key:"Tab",description:"Toggle pane focus"}]},{title:"Staging",entries:[{key:"s",description:"Stage file"},{key:"U",description:"Unstage file"},{key:"A",description:"Stage all"},{key:"Z",description:"Unstage all"},{key:"Space",description:"Toggle stage"}]},{title:"Actions",entries:[{key:"c",description:"Commit panel"},{key:"r",description:"Refresh"},{key:"q",description:"Quit"}]},{title:"Resize",entries:[{key:"-",description:"Shrink top pane"},{key:"+",description:"Grow top pane"}]},{title:"Tabs",entries:[{key:"1",description:"Diff view"},{key:"2",description:"Commit panel"},{key:"3",description:"History view"},{key:"4",description:"Compare view"},{key:"5",description:"Explorer view"}]},{title:"Toggles",entries:[{key:"m",description:"Mouse mode"},{key:"w",description:"Wrap mode"},{key:"f",description:"Follow mode"},{key:"t",description:"Theme picker"},{key:"?",description:"This help"}]},{title:"Explorer",entries:[{key:"Enter",description:"Enter directory"},{key:"Backspace",description:"Go up"}]},{title:"Compare",entries:[{key:"b",description:"Base branch picker"},{key:"u",description:"Toggle uncommitted"}]},{title:"Diff",entries:[{key:"d",description:"Discard changes"}]}];class a7{box;screen;onClose;constructor($,J){this.screen=$,this.onClose=J;let{width:K,height:Z}=$,X=K>=90,Q=X?Math.min(80,K-4):Math.min(42,K-4),z=Math.min(this.calculateHeight(X),Z-4);this.box=P$.box({parent:$,top:"center",left:"center",width:Q,height:z,border:{type:"line"},style:{border:{fg:"cyan"}},tags:!0,keys:!0,scrollable:!0,alwaysScroll:!0}),this.setupKeyHandlers(),this.render(X,Q)}calculateHeight($){if($){let J=Math.ceil(u.length/2),K=u.slice(0,J),Z=u.slice(J),X=K.reduce((z,q)=>z+q.entries.length+2,0),Q=Z.reduce((z,q)=>z+q.entries.length+2,0);return Math.max(X,Q)+5}else return u.reduce((J,K)=>J+K.entries.length+2,0)+5}setupKeyHandlers(){this.box.key(["escape","enter","?","q"],()=>{this.close(),this.onClose()}),this.box.on("click",()=>{this.close(),this.onClose()})}visibleWidth($){return $.replace(/\{[^}]+\}/g,"").length}padToVisible($,J){let K=this.visibleWidth($),Z=Math.max(0,J-K);return $+" ".repeat(Z)}render($,J){let K=[];if(K.push("{bold}{cyan-fg} Keyboard Shortcuts{/cyan-fg}{/bold}"),K.push(""),$){let Z=Math.ceil(u.length/2),X=u.slice(0,Z),Q=u.slice(Z),z=Math.floor((J-6)/2),q=this.renderGroups(X,z),Y=this.renderGroups(Q,z),U=Math.max(q.length,Y.length);for(let V=0;V<U;V++){let B=this.padToVisible(q[V]||"",z),G=Y[V]||"";K.push(B+" "+G)}}else for(let Z of u){K.push(`{bold}{gray-fg}${Z.title}{/gray-fg}{/bold}`);for(let X of Z.entries)K.push(` {cyan-fg}${X.key.padEnd(10)}{/cyan-fg} ${X.description}`);K.push("")}K.push(""),K.push("{gray-fg}Press Esc, Enter, or ? to close{/gray-fg}"),this.box.setContent(K.join(`
|
|
39
|
+
`)),this.screen.render()}renderGroups($,J){let K=[];for(let Z of $){K.push(`{bold}{gray-fg}${Z.title}{/gray-fg}{/bold}`);for(let X of Z.entries)K.push(` {cyan-fg}${X.key.padEnd(10)}{/cyan-fg} ${X.description}`);K.push("")}return K}close(){this.box.destroy()}focus(){this.box.focus()}}import S$ from"neo-blessed";class s7{box;screen;branches;selectedIndex;currentBranch;onSelect;onCancel;constructor($,J,K,Z,X){if(this.screen=$,this.branches=J,this.currentBranch=K,this.onSelect=Z,this.onCancel=X,this.selectedIndex=K?J.indexOf(K):0,this.selectedIndex<0)this.selectedIndex=0;let Q=50,q=Math.min(J.length,15)+6;this.box=S$.box({parent:$,top:"center",left:"center",width:Q,height:q,border:{type:"line"},style:{border:{fg:"cyan"}},tags:!0,keys:!0,scrollable:!0,alwaysScroll:!0}),this.setupKeyHandlers(),this.render()}setupKeyHandlers(){this.box.key(["escape","q"],()=>{this.close(),this.onCancel()}),this.box.key(["enter","space"],()=>{let $=this.branches[this.selectedIndex];if($)this.close(),this.onSelect($)}),this.box.key(["up","k"],()=>{this.selectedIndex=Math.max(0,this.selectedIndex-1),this.render()}),this.box.key(["down","j"],()=>{this.selectedIndex=Math.min(this.branches.length-1,this.selectedIndex+1),this.render()})}render(){let $=[];if($.push("{bold}{cyan-fg} Select Base Branch{/cyan-fg}{/bold}"),$.push(""),this.branches.length===0)$.push("{gray-fg}No branches found{/gray-fg}");else for(let J=0;J<this.branches.length;J++){let K=this.branches[J],Z=J===this.selectedIndex,X=K===this.currentBranch,Q=Z?"{cyan-fg}{bold}> ":" ";if(Q+=K,Z)Q+="{/bold}{/cyan-fg}";if(X)Q+=" {gray-fg}(current){/gray-fg}";$.push(Q)}$.push(""),$.push("{gray-fg}j/k: navigate | Enter: select | Esc: cancel{/gray-fg}"),this.box.setContent($.join(`
|
|
40
|
+
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import b$ from"neo-blessed";class n7{box;screen;filePath;onConfirm;onCancel;constructor($,J,K,Z){this.screen=$,this.filePath=J,this.onConfirm=K,this.onCancel=Z;let X=Math.min(60,Math.max(40,J.length+20)),Q=7;this.box=b$.box({parent:$,top:"center",left:"center",width:X,height:Q,border:{type:"line"},style:{border:{fg:"yellow"}},tags:!0,keys:!0}),this.setupKeyHandlers(),this.render()}setupKeyHandlers(){this.box.key(["y","Y"],()=>{this.close(),this.onConfirm()}),this.box.key(["n","N","escape","q"],()=>{this.close(),this.onCancel()})}render(){let $=[];$.push("{bold}{yellow-fg} Discard Changes?{/yellow-fg}{/bold}"),$.push("");let J=this.box.width-6,K=this.filePath.length>J?"..."+this.filePath.slice(-(J-3)):this.filePath;$.push(`{white-fg}${K}{/white-fg}`),$.push(""),$.push("{gray-fg}Press {/gray-fg}{green-fg}y{/green-fg}{gray-fg} to confirm, {/gray-fg}{red-fg}n{/red-fg}{gray-fg} or Esc to cancel{/gray-fg}"),this.box.setContent($.join(`
|
|
41
|
+
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import Y9 from"neo-blessed";var _7=15;function x$($,J){let K=$.toLowerCase(),Z=J.toLowerCase(),X=0,Q=0,z=-1;for(let q=0;q<Z.length&&X<K.length;q++)if(Z[q]===K[X]){if(z===q-1)Q+=10;if(q===0||Z[q-1]==="/"||Z[q-1]===".")Q+=5;Q+=1,z=q,X++}if(X<K.length)return-1;return Q+=Math.max(0,50-J.length),Q}function w$($,J){if(!$)return J;let K=$.toLowerCase(),Z=J.toLowerCase(),X="",Q=0;for(let z=0;z<J.length;z++)if(Q<K.length&&Z[z]===K[Q])X+=`{yellow-fg}${J[z]}{/yellow-fg}`,Q++;else X+=J[z];return X}class i7{box;textbox;screen;allPaths;results=[];selectedIndex=0;query="";onSelect;onCancel;constructor($,J,K,Z){this.screen=$,this.allPaths=J,this.onSelect=K,this.onCancel=Z;let X=Math.min(80,$.width-10),Q=_7+6;this.box=Y9.box({parent:$,top:"center",left:"center",width:X,height:Q,border:{type:"line"},style:{border:{fg:"cyan"}},tags:!0,keys:!1}),this.textbox=Y9.textarea({parent:this.box,top:1,left:1,width:X-4,height:1,inputOnFocus:!0,style:{fg:"white",bg:"default"}}),this.setupKeyHandlers(),this.updateResults(),this.render()}setupKeyHandlers(){this.textbox.key(["escape"],()=>{this.close(),this.onCancel()}),this.textbox.key(["enter"],()=>{if(this.results.length>0){let $=this.results[this.selectedIndex];this.close(),this.onSelect($.path)}}),this.textbox.key(["C-j","down"],()=>{this.selectedIndex=Math.min(this.results.length-1,this.selectedIndex+1),this.render()}),this.textbox.key(["C-k","up"],()=>{this.selectedIndex=Math.max(0,this.selectedIndex-1),this.render()}),this.textbox.key(["tab"],()=>{this.selectedIndex=(this.selectedIndex+1)%Math.max(1,this.results.length),this.render()}),this.textbox.key(["S-tab"],()=>{this.selectedIndex=(this.selectedIndex-1+this.results.length)%Math.max(1,this.results.length),this.render()}),this.textbox.on("keypress",()=>{setImmediate(()=>{let $=this.textbox.getValue()||"";if($!==this.query)this.query=$,this.selectedIndex=0,this.updateResults(),this.render()})})}updateResults(){if(!this.query){this.results=this.allPaths.slice(0,_7).map((J)=>({path:J,score:0}));return}let $=[];for(let J of this.allPaths){let K=x$(this.query,J);if(K>=0)$.push({path:J,score:K})}$.sort((J,K)=>K.score-J.score),this.results=$.slice(0,_7)}render(){let $=[],J=this.box.width-4;if($.push("{bold}{cyan-fg}Find File{/cyan-fg}{/bold}"),$.push(""),$.push(""),this.results.length===0&&this.query)$.push("{gray-fg}No matches{/gray-fg}");else for(let K=0;K<this.results.length;K++){let Z=this.results[K],X=K===this.selectedIndex,Q=Z.path,z=J-4;if(Q.length>z)Q="…"+Q.slice(-(z-1));let q=w$(this.query,Q);if(X)$.push(`{cyan-fg}{bold}> ${q}{/bold}{/cyan-fg}`);else $.push(` ${q}`)}while($.length<_7+3)$.push("");$.push("{gray-fg}Enter: select | Esc: cancel | Ctrl+j/k or ↑↓: navigate{/gray-fg}"),this.box.setContent($.join(`
|
|
42
|
+
`)),this.screen.render()}close(){this.textbox.destroy(),this.box.destroy()}focus(){this.textbox.focus()}}import{EventEmitter as u$}from"node:events";function U9($,J,K){if(!$.trim())return{valid:!1,error:"Commit message cannot be empty"};if(J===0&&!K)return{valid:!1,error:"No changes staged for commit"};return{valid:!0,error:null}}function B9($){return $.trim()}var G9={message:"",amend:!1,isCommitting:!1,error:null,inputFocused:!1};class t7 extends u${_state={...G9};getHeadMessage;onCommit;onSuccess;stagedCount=0;constructor($){super();this.getHeadMessage=$.getHeadMessage,this.onCommit=$.onCommit,this.onSuccess=$.onSuccess}get state(){return this._state}update($){this._state={...this._state,...$},this.emit("change",this._state)}setStagedCount($){this.stagedCount=$}setMessage($){this.update({message:$,error:null})}setInputFocused($){this.update({inputFocused:$}),this.emit("focus-change",$)}async toggleAmend(){let $=!this._state.amend;if(this.update({amend:$}),$&&!this._state.message)try{let J=await this.getHeadMessage();if(J)this.update({message:J})}catch{}}async submit(){let $=U9(this._state.message,this.stagedCount,this._state.amend);if(!$.valid){this.update({error:$.error});return}this.update({isCommitting:!0,error:null});try{await this.onCommit(B9(this._state.message),this._state.amend),this.update({message:"",amend:!1,isCommitting:!1,inputFocused:!1}),this.onSuccess()}catch(J){this.update({isCommitting:!1,error:J instanceof Error?J.message:"Commit failed"})}}reset(){this._state={...G9},this.emit("change",this._state)}}import{EventEmitter as p$}from"node:events";var g$={currentPane:"files",bottomTab:"diff",selectedIndex:0,fileListScrollOffset:0,diffScrollOffset:0,historyScrollOffset:0,compareScrollOffset:0,explorerScrollOffset:0,explorerFileScrollOffset:0,historySelectedIndex:0,compareSelectedIndex:0,includeUncommitted:!1,explorerSelectedIndex:0,wrapMode:!1,autoTabEnabled:!1,mouseEnabled:!0,hideHiddenFiles:!0,hideGitignored:!0,splitRatio:0.4,activeModal:null,pendingDiscard:null,commitInputFocused:!1};class e7 extends p${_state;constructor($={}){super();this._state={...g$,...$}}get state(){return this._state}update($){this._state={...this._state,...$},this.emit("change",this._state)}setPane($){if(this._state.currentPane!==$)this.update({currentPane:$}),this.emit("pane-change",$)}setTab($){if(this._state.bottomTab!==$){let J={diff:"files",commit:"commit",history:"history",compare:"compare",explorer:"explorer"};this.update({bottomTab:$,currentPane:J[$]}),this.emit("tab-change",$)}}setSelectedIndex($){if(this._state.selectedIndex!==$)this.update({selectedIndex:$}),this.emit("selection-change",$)}setFileListScrollOffset($){this.update({fileListScrollOffset:Math.max(0,$)}),this.emit("scroll-change",{type:"fileList",offset:$})}setDiffScrollOffset($){this.update({diffScrollOffset:Math.max(0,$)}),this.emit("scroll-change",{type:"diff",offset:$})}setHistoryScrollOffset($){this.update({historyScrollOffset:Math.max(0,$)}),this.emit("scroll-change",{type:"history",offset:$})}setCompareScrollOffset($){this.update({compareScrollOffset:Math.max(0,$)}),this.emit("scroll-change",{type:"compare",offset:$})}setExplorerScrollOffset($){this.update({explorerScrollOffset:Math.max(0,$)}),this.emit("scroll-change",{type:"explorer",offset:$})}setExplorerFileScrollOffset($){this.update({explorerFileScrollOffset:Math.max(0,$)}),this.emit("scroll-change",{type:"explorerFile",offset:$})}setHistorySelectedIndex($){this.update({historySelectedIndex:Math.max(0,$)})}setCompareSelectedIndex($){this.update({compareSelectedIndex:Math.max(0,$)})}toggleIncludeUncommitted(){this.update({includeUncommitted:!this._state.includeUncommitted})}setExplorerSelectedIndex($){this.update({explorerSelectedIndex:Math.max(0,$)})}toggleWrapMode(){this.update({wrapMode:!this._state.wrapMode,diffScrollOffset:0})}toggleAutoTab(){this.update({autoTabEnabled:!this._state.autoTabEnabled})}toggleMouse(){this.update({mouseEnabled:!this._state.mouseEnabled})}toggleHideHiddenFiles(){this.update({hideHiddenFiles:!this._state.hideHiddenFiles})}toggleHideGitignored(){this.update({hideGitignored:!this._state.hideGitignored})}adjustSplitRatio($){let J=Math.min(0.85,Math.max(0.15,this._state.splitRatio+$));this.update({splitRatio:J})}setSplitRatio($){this.update({splitRatio:Math.min(0.85,Math.max(0.15,$))})}openModal($){this.update({activeModal:$}),this.emit("modal-change",$)}closeModal(){this.update({activeModal:null}),this.emit("modal-change",null)}toggleModal($){if(this._state.activeModal===$)this.closeModal();else this.openModal($)}setPendingDiscard($){this.update({pendingDiscard:$})}setCommitInputFocused($){this.update({commitInputFocused:$})}togglePane(){let{bottomTab:$,currentPane:J}=this._state;if($==="diff"||$==="commit")this.setPane(J==="files"?"diff":"files");else if($==="history")this.setPane(J==="history"?"diff":"history");else if($==="compare")this.setPane(J==="compare"?"diff":"compare");else if($==="explorer")this.setPane(J==="explorer"?"diff":"explorer")}resetForNewRepo(){this._state={...this._state,selectedIndex:0,fileListScrollOffset:0,diffScrollOffset:0,historySelectedIndex:0,historyScrollOffset:0,compareSelectedIndex:0,compareScrollOffset:0,explorerSelectedIndex:0,explorerScrollOffset:0,explorerFileScrollOffset:0},this.emit("change",this._state)}}import*as C from"node:path";import*as p from"node:fs";import{execFileSync as l$}from"node:child_process";import{watch as x9}from"chokidar";import{EventEmitter as o$}from"node:events";import w9 from"ignore";class j9{queue=[];isProcessing=!1;pendingMutations=0;refreshScheduled=!1;enqueue($){return new Promise((J,K)=>{this.queue.push({execute:$,resolve:J,reject:K}),this.processNext()})}enqueueMutation($){return this.pendingMutations++,this.enqueue($).finally(()=>{this.pendingMutations--})}hasPendingMutations(){return this.pendingMutations>0}scheduleRefresh($){if(this.pendingMutations>0)return;if(this.refreshScheduled)return;this.refreshScheduled=!0,this.enqueue(async()=>{this.refreshScheduled=!1,await $()}).catch(()=>{this.refreshScheduled=!1})}isBusy(){return this.isProcessing||this.queue.length>0}async processNext(){if(this.isProcessing||this.queue.length===0)return;this.isProcessing=!0;let $=this.queue.shift();try{let J=await $.execute();$.resolve(J)}catch(J){$.reject(J instanceof Error?J:Error(String(J)))}finally{this.isProcessing=!1,this.processNext()}}}var $8=new Map;function k9($){let J=$8.get($);if(!J)J=new j9,$8.set($,J);return J}function _9($){$8.delete($)}import{simpleGit as P}from"simple-git";import*as H9 from"node:fs";import*as D9 from"node:path";function O9($){let J=new Map;for(let K of $.trim().split(`
|
|
43
|
+
`)){if(!K)continue;let Z=K.split("\t");if(Z.length>=3){let X=Z[0]==="-"?0:parseInt(Z[0],10),Q=Z[1]==="-"?0:parseInt(Z[1],10),z=Z.slice(2).join("\t");J.set(z,{insertions:X,deletions:Q})}}return J}async function m$($,J){try{let K=D9.join($,J);return(await H9.promises.readFile(K,"utf-8")).split(`
|
|
44
|
+
`).filter((X)=>X.length>0).length}catch{return 0}}function M9($){switch($){case"M":return"modified";case"A":return"added";case"D":return"deleted";case"?":return"untracked";case"R":return"renamed";case"C":return"copied";default:return"modified"}}async function J8($){let J=P($);try{if(!await J.checkIsRepo())return{files:[],branch:{current:"",ahead:0,behind:0},isRepo:!1};let Z=await J.status(),X=[];for(let j of Z.staged)X.push({path:j,status:"added",staged:!0});for(let j of Z.modified)if(!X.find((D)=>D.path===j&&D.staged))X.push({path:j,status:"modified",staged:!1});for(let j of Z.deleted)X.push({path:j,status:"deleted",staged:!1});for(let j of Z.not_added)X.push({path:j,status:"untracked",staged:!1});for(let j of Z.renamed)X.push({path:j.to,originalPath:j.from,status:"renamed",staged:!0});let Q=[],z=new Set,q=Z.files.filter((j)=>j.working_dir==="?").map((j)=>j.path),Y=await e($,q);for(let j of Z.files){if(j.index==="!"||j.working_dir==="!"||Y.has(j.path))continue;let O=`${j.path}-${j.index!==" "&&j.index!=="?"}`;if(z.has(O))continue;if(z.add(O),j.index&&j.index!==" "&&j.index!=="?")Q.push({path:j.path,status:M9(j.index),staged:!0});if(j.working_dir&&j.working_dir!==" ")Q.push({path:j.path,status:j.working_dir==="?"?"untracked":M9(j.working_dir),staged:!1})}let[U,V]=await Promise.all([J.diff(["--cached","--numstat"]).catch(()=>""),J.diff(["--numstat"]).catch(()=>"")]),B=O9(U),G=O9(V);for(let j of Q){let O=j.staged?B.get(j.path):G.get(j.path);if(O)j.insertions=O.insertions,j.deletions=O.deletions}let k=Q.filter((j)=>j.status==="untracked");if(k.length>0){let j=await Promise.all(k.map((O)=>m$($,O.path)));for(let O=0;O<k.length;O++)k[O].insertions=j[O],k[O].deletions=0}return{files:Q,branch:{current:Z.current||"HEAD",tracking:Z.tracking||void 0,ahead:Z.ahead,behind:Z.behind},isRepo:!0}}catch{return{files:[],branch:{current:"",ahead:0,behind:0},isRepo:!1}}}async function v9($,J){await P($).add(J)}async function A9($,J){await P($).reset(["HEAD","--",J])}async function T9($){await P($).add("-A")}async function N9($){await P($).reset(["HEAD"])}async function W9($,J){await P($).checkout(["--",J])}async function F9($,J,K=!1){await P($).commit(J,void 0,K?{"--amend":null}:void 0)}async function E9($){let J=P($);try{return(await J.log({n:1})).latest?.message||""}catch{return""}}async function L9($,J=50){let K=P($);try{return(await K.log({n:J})).all.map((X)=>({hash:X.hash,shortHash:X.hash.slice(0,7),message:X.message.split(`
|
|
45
|
+
`)[0],author:X.author_name,date:new Date(X.date),refs:X.refs||""}))}catch{return[]}}import{execSync as f$}from"node:child_process";import{simpleGit as $7}from"simple-git";function h$($){let J=$.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);if(J)return{oldStart:parseInt(J[1],10),newStart:parseInt(J[2],10)};return null}function O7($){let J=$.split(`
|
|
46
|
+
`),K=[],Z=0,X=0;for(let Q of J)if(Q.startsWith("diff --git")||Q.startsWith("index ")||Q.startsWith("---")||Q.startsWith("+++")||Q.startsWith("new file")||Q.startsWith("deleted file")||Q.startsWith("Binary files")||Q.startsWith("similarity index")||Q.startsWith("rename from")||Q.startsWith("rename to"))K.push({type:"header",content:Q});else if(Q.startsWith("@@")){let z=h$(Q);if(z)Z=z.oldStart,X=z.newStart;K.push({type:"hunk",content:Q})}else if(Q.startsWith("+"))K.push({type:"addition",content:Q,newLineNum:X++});else if(Q.startsWith("-"))K.push({type:"deletion",content:Q,oldLineNum:Z++});else K.push({type:"context",content:Q,oldLineNum:Z++,newLineNum:X++});return K}async function J7($,J,K=!1){let Z=$7($);try{let X=[];if(K)X.push("--cached");if(J)X.push("--",J);let Q=await Z.diff(X),z=O7(Q);return{raw:Q,lines:z}}catch{return{raw:"",lines:[]}}}async function K8($,J){try{let K=f$(`cat "${J}"`,{cwd:$,encoding:"utf-8"}),Z=[{type:"header",content:`diff --git a/${J} b/${J}`},{type:"header",content:"new file mode 100644"},{type:"header",content:"--- /dev/null"},{type:"header",content:`+++ b/${J}`}],X=K.split(`
|
|
47
|
+
`);Z.push({type:"hunk",content:`@@ -0,0 +1,${X.length} @@`});let Q=1;for(let q of X)Z.push({type:"addition",content:"+"+q,newLineNum:Q++});return{raw:Z.map((q)=>q.content).join(`
|
|
48
|
+
`),lines:Z}}catch{return{raw:"",lines:[]}}}async function I9($){return J7($,void 0,!0)}async function Z8($){let J=$7($),K=new Set,Z=[];try{let X=await J.raw(["log","--oneline","--decorate=short","--all","-n","200"]),Q=/\(([^)]+)\)/g;for(let z of X.split(`
|
|
49
|
+
`)){let q=Q.exec(z);if(q){let Y=q[1].split(",").map((U)=>U.trim());for(let U of Y){if(U.startsWith("HEAD")||U.startsWith("tag:")||!U.includes("/"))continue;let V=U.replace(/^.*-> /,"");if(V.includes("/")&&!K.has(V))K.add(V),Z.push(V)}}Q.lastIndex=0}if(Z.length>0)Z.sort((z,q)=>{let Y=z.split("/").slice(1).join("/"),U=q.split("/").slice(1).join("/"),V=Y==="main"||Y==="master",B=U==="main"||U==="master";if(V&&!B)return-1;if(!V&&B)return 1;if(V&&B){let G=z.startsWith("origin/"),k=q.startsWith("origin/");if(G&&!k)return 1;if(!G&&k)return-1}return 0})}catch{}return[...new Set(Z)]}async function R9($){return(await Z8($))[0]??null}async function X8($,J){let K=$7($),X=(await K.raw(["merge-base",J,"HEAD"])).trim(),Q=await K.raw(["diff","--numstat",`${X}...HEAD`]),z=await K.raw(["diff","--name-status",`${X}...HEAD`]),q=await K.raw(["diff",`${X}...HEAD`]),Y=Q.trim().split(`
|
|
50
|
+
`).filter((_)=>_),U=new Map;for(let _ of Y){let M=_.split("\t");if(M.length>=3){let v=M[0]==="-"?0:parseInt(M[0],10),W=M[1]==="-"?0:parseInt(M[1],10),N=M.slice(2).join("\t");U.set(N,{additions:v,deletions:W})}}let V=z.trim().split(`
|
|
51
|
+
`).filter((_)=>_),B=new Map;for(let _ of V){let M=_.split("\t");if(M.length>=2){let v=M[0][0],W=M[M.length-1],N;switch(v){case"A":N="added";break;case"D":N="deleted";break;case"R":N="renamed";break;default:N="modified"}B.set(W,N)}}let G=[],k=q.split(/(?=^diff --git )/m).filter((_)=>_.trim());for(let _ of k){let M=_.match(/^diff --git a\/.+ b\/(.+)$/m);if(!M)continue;let v=M[1],W=O7(_),N=U.get(v)||{additions:0,deletions:0},F=B.get(v)||"modified";G.push({path:v,status:F,additions:N.additions,deletions:N.deletions,diff:{raw:_,lines:W}})}let j=0,O=0;for(let _ of G)j+=_.additions,O+=_.deletions;let H=(await K.status()).files.length,T=(await K.log({from:X,to:"HEAD"})).all.map((_)=>({hash:_.hash,shortHash:_.hash.slice(0,7),message:_.message.split(`
|
|
52
|
+
`)[0],author:_.author_name,date:new Date(_.date),refs:_.refs||""}));return G.sort((_,M)=>_.path.localeCompare(M.path)),{baseBranch:J,stats:{filesChanged:G.length,additions:j,deletions:O},files:G,commits:T,uncommittedCount:H}}async function Q8($,J){let K=$7($);try{let Z=await K.raw(["show",J,"--format="]),X=O7(Z);return{raw:Z,lines:X}}catch{return{raw:"",lines:[]}}}async function y9($,J){let K=$7($),Z=await X8($,J),X=await K.diff(["--cached","--numstat"]),Q=await K.diff(["--numstat"]),z=await K.diff(["--cached"]),q=await K.diff([]),Y=new Map;for(let _ of X.trim().split(`
|
|
53
|
+
`).filter((M)=>M)){let M=_.split("\t");if(M.length>=3){let v=M[0]==="-"?0:parseInt(M[0],10),W=M[1]==="-"?0:parseInt(M[1],10),N=M.slice(2).join("\t");Y.set(N,{additions:v,deletions:W,staged:!0,unstaged:!1})}}for(let _ of Q.trim().split(`
|
|
54
|
+
`).filter((M)=>M)){let M=_.split("\t");if(M.length>=3){let v=M[0]==="-"?0:parseInt(M[0],10),W=M[1]==="-"?0:parseInt(M[1],10),N=M.slice(2).join("\t"),F=Y.get(N);if(F)F.additions+=v,F.deletions+=W,F.unstaged=!0;else Y.set(N,{additions:v,deletions:W,staged:!1,unstaged:!0})}}let U=await K.status(),V=new Map;for(let _ of U.files)if(_.index==="A"||_.working_dir==="?")V.set(_.path,"added");else if(_.index==="D"||_.working_dir==="D")V.set(_.path,"deleted");else if(_.index==="R")V.set(_.path,"renamed");else V.set(_.path,"modified");let B=[],k=(z+q).split(/(?=^diff --git )/m).filter((_)=>_.trim()),j=new Set;for(let _ of k){let M=_.match(/^diff --git a\/.+ b\/(.+)$/m);if(!M)continue;let v=M[1];if(j.has(v))continue;j.add(v);let W=O7(_),N=Y.get(v)||{additions:0,deletions:0},F=V.get(v)||"modified";B.push({path:v,status:F,additions:N.additions,deletions:N.deletions,diff:{raw:_,lines:W},isUncommitted:!0})}let O=new Set(Z.files.map((_)=>_.path)),D=[];for(let _ of Z.files){let M=B.find((v)=>v.path===_.path);if(M)D.push(_),D.push(M);else D.push(_)}for(let _ of B)if(!O.has(_.path))D.push(_);let H=0,A=0,T=new Set;for(let _ of D){if(!T.has(_.path))T.add(_.path);H+=_.additions,A+=_.deletions}return D.sort((_,M)=>_.path.localeCompare(M.path)),{baseBranch:Z.baseBranch,stats:{filesChanged:T.size,additions:H,deletions:A},files:D,commits:Z.commits,uncommittedCount:Z.uncommittedCount}}import*as S from"node:fs";import*as h from"node:path";import*as C9 from"node:os";var M7=h.join(C9.homedir(),".cache","diffstalker","base-branches.json");function c$(){let $=h.dirname(M7);if(!S.existsSync($))S.mkdirSync($,{recursive:!0})}function P9(){try{if(S.existsSync(M7))return JSON.parse(S.readFileSync(M7,"utf-8"))}catch{}return{}}function d$($){c$(),S.writeFileSync(M7,JSON.stringify($,null,2)+`
|
|
55
|
+
`)}function S9($){let J=P9(),K=h.resolve($);return J[K]}function b9($,J){let K=P9(),Z=h.resolve($);K[Z]=J,d$(K)}class u9 extends o${repoPath;queue;gitWatcher=null;workingDirWatcher=null;ignorers=new Map;diffDebounceTimer=null;_state={status:null,diff:null,selectedFile:null,isLoading:!1,error:null};_compareState={compareDiff:null,compareBaseBranch:null,compareLoading:!1,compareError:null};_historyState={commits:[],selectedCommit:null,commitDiff:null,isLoading:!1};_compareSelectionState={type:null,index:0,diff:null};constructor($){super();this.repoPath=$,this.queue=k9($)}get state(){return this._state}get compareState(){return this._compareState}get historyState(){return this._historyState}get compareSelectionState(){return this._compareSelectionState}updateState($){this._state={...this._state,...$},this.emit("state-change",this._state)}updateCompareState($){this._compareState={...this._compareState,...$},this.emit("compare-state-change",this._compareState)}updateHistoryState($){this._historyState={...this._historyState,...$},this.emit("history-state-change",this._historyState)}updateCompareSelectionState($){this._compareSelectionState={...this._compareSelectionState,...$},this.emit("compare-selection-change",this._compareSelectionState)}loadGitignores(){let $=new Map,J=w9();J.add(".git");let K=C.join(this.repoPath,".gitignore");if(p.existsSync(K))J.add(p.readFileSync(K,"utf-8"));let Z=C.join(this.repoPath,".git","info","exclude");if(p.existsSync(Z))J.add(p.readFileSync(Z,"utf-8"));$.set("",J);try{let X=l$("git",["ls-files","-z","--cached","--others","**/.gitignore"],{cwd:this.repoPath,encoding:"utf-8"});for(let Q of X.split("\x00")){if(!Q||Q===".gitignore")continue;if(!Q.endsWith(".gitignore"))continue;let z=C.dirname(Q),q=C.join(this.repoPath,Q);try{let Y=p.readFileSync(q,"utf-8"),U=w9();U.add(Y),$.set(z,U)}catch{}}}catch{}return $}startWatching(){let $=C.join(this.repoPath,".git");if(!p.existsSync($))return;let J=C.join($,"index"),K=C.join($,"HEAD"),Z=C.join($,"refs"),X=C.join(this.repoPath,".gitignore");this.gitWatcher=x9([J,K,Z,X],{persistent:!0,ignoreInitial:!0,usePolling:!0,interval:100}),this.ignorers=this.loadGitignores(),this.workingDirWatcher=x9(this.repoPath,{persistent:!0,ignoreInitial:!0,ignored:(z)=>{let q=C.relative(this.repoPath,z);if(!q)return!1;let Y=q.split("/");for(let U=0;U<Y.length;U++){let V=U===0?"":Y.slice(0,U).join("/"),B=this.ignorers.get(V);if(B){let G=U===0?q:Y.slice(U).join("/");if(B.ignores(G))return!0}}return!1},awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}});let Q=()=>this.scheduleRefresh();this.gitWatcher.on("change",(z)=>{if(z===X)this.ignorers=this.loadGitignores();Q()}),this.gitWatcher.on("add",Q),this.gitWatcher.on("unlink",Q),this.gitWatcher.on("error",(z)=>{let q=z instanceof Error?z.message:String(z);this.emit("error",`Git watcher error: ${q}`)}),this.workingDirWatcher.on("change",Q),this.workingDirWatcher.on("add",Q),this.workingDirWatcher.on("unlink",Q),this.workingDirWatcher.on("error",(z)=>{let q=z instanceof Error?z.message:String(z);this.emit("error",`Working dir watcher error: ${q}`)})}dispose(){if(this.diffDebounceTimer)clearTimeout(this.diffDebounceTimer);this.gitWatcher?.close(),this.workingDirWatcher?.close(),_9(this.repoPath)}scheduleRefresh(){this.queue.scheduleRefresh(async()=>{if(await this.doRefresh(),this._historyState.commits.length>0)await this.doLoadHistory();if(this._compareState.compareBaseBranch)await this.doRefreshCompareDiff(!1)})}scheduleStatusRefresh(){this.queue.scheduleRefresh(async()=>{let $=await J8(this.repoPath);if(!$.isRepo){this.updateState({status:$,diff:null,isLoading:!1,error:"Not a git repository"});return}this.updateState({status:$,isLoading:!1})})}async refresh(){await this.queue.enqueue(()=>this.doRefresh())}async doRefresh(){this.updateState({isLoading:!0,error:null});try{let $=await J8(this.repoPath);if(!$.isRepo){this.updateState({status:$,diff:null,isLoading:!1,error:"Not a git repository"});return}this.updateState({status:$});let J=await J7(this.repoPath,void 0,!1),K,Z=this._state.selectedFile;if(Z){let X=$.files.find((Q)=>Q.path===Z.path&&Q.staged===Z.staged);if(X)if(X.status==="untracked")K=await K8(this.repoPath,X.path);else K=await J7(this.repoPath,X.path,X.staged);else K=J,this.updateState({selectedFile:null})}else K=J;this.updateState({diff:K,isLoading:!1})}catch($){this.updateState({isLoading:!1,error:$ instanceof Error?$.message:"Unknown error"})}}selectFile($){if(this.updateState({selectedFile:$}),!this._state.status?.isRepo)return;if(this.diffDebounceTimer)clearTimeout(this.diffDebounceTimer),this.diffDebounceTimer=setTimeout(()=>{this.diffDebounceTimer=null,this.fetchDiffForSelection()},20);else this.fetchDiffForSelection(),this.diffDebounceTimer=setTimeout(()=>{this.diffDebounceTimer=null},20)}fetchDiffForSelection(){let $=this._state.selectedFile;this.queue.enqueue(async()=>{if($!==this._state.selectedFile)return;if($){let J;if($.status==="untracked")J=await K8(this.repoPath,$.path);else J=await J7(this.repoPath,$.path,$.staged);if($===this._state.selectedFile)this.updateState({diff:J})}else{let J=await I9(this.repoPath);if(this._state.selectedFile===null)this.updateState({diff:J})}}).catch((J)=>{this.updateState({error:`Failed to load diff: ${J instanceof Error?J.message:String(J)}`})})}async stage($){try{await this.queue.enqueueMutation(()=>v9(this.repoPath,$.path)),this.scheduleStatusRefresh()}catch(J){await this.refresh(),this.updateState({error:`Failed to stage ${$.path}: ${J instanceof Error?J.message:String(J)}`})}}async unstage($){try{await this.queue.enqueueMutation(()=>A9(this.repoPath,$.path)),this.scheduleStatusRefresh()}catch(J){await this.refresh(),this.updateState({error:`Failed to unstage ${$.path}: ${J instanceof Error?J.message:String(J)}`})}}async discard($){if($.staged||$.status==="untracked")return;try{await this.queue.enqueueMutation(()=>W9(this.repoPath,$.path)),await this.refresh()}catch(J){this.updateState({error:`Failed to discard ${$.path}: ${J instanceof Error?J.message:String(J)}`})}}async stageAll(){try{await this.queue.enqueueMutation(()=>T9(this.repoPath)),await this.refresh()}catch($){this.updateState({error:`Failed to stage all: ${$ instanceof Error?$.message:String($)}`})}}async unstageAll(){try{await this.queue.enqueueMutation(()=>N9(this.repoPath)),await this.refresh()}catch($){this.updateState({error:`Failed to unstage all: ${$ instanceof Error?$.message:String($)}`})}}async commit($,J=!1){try{await this.queue.enqueue(()=>F9(this.repoPath,$,J)),await this.refresh()}catch(K){this.updateState({error:`Failed to commit: ${K instanceof Error?K.message:String(K)}`})}}async getHeadCommitMessage(){return this.queue.enqueue(()=>E9(this.repoPath))}async refreshCompareDiff($=!1){this.updateCompareState({compareLoading:!0,compareError:null});try{await this.queue.enqueue(()=>this.doRefreshCompareDiff($))}catch(J){this.updateCompareState({compareLoading:!1,compareError:`Failed to load compare diff: ${J instanceof Error?J.message:String(J)}`})}}async doRefreshCompareDiff($){let J=this._compareState.compareBaseBranch;if(!J)J=S9(this.repoPath)??await R9(this.repoPath),this.updateCompareState({compareBaseBranch:J});if(J){let K=$?await y9(this.repoPath,J):await X8(this.repoPath,J);this.updateCompareState({compareDiff:K,compareLoading:!1})}else this.updateCompareState({compareDiff:null,compareLoading:!1,compareError:"No base branch found"})}async getCandidateBaseBranches(){return Z8(this.repoPath)}async setCompareBaseBranch($,J=!1){this.updateCompareState({compareBaseBranch:$}),b9(this.repoPath,$),await this.refreshCompareDiff(J)}async loadHistory($=100){this.updateHistoryState({isLoading:!0});try{await this.queue.enqueue(()=>this.doLoadHistory($))}catch(J){this.updateHistoryState({isLoading:!1}),this.updateState({error:`Failed to load history: ${J instanceof Error?J.message:String(J)}`})}}async doLoadHistory($=100){let J=await L9(this.repoPath,$);this.updateHistoryState({commits:J,isLoading:!1})}async selectHistoryCommit($){if(this.updateHistoryState({selectedCommit:$,commitDiff:null}),!$)return;try{await this.queue.enqueue(async()=>{let J=await Q8(this.repoPath,$.hash);this.updateHistoryState({commitDiff:J})})}catch(J){this.updateState({error:`Failed to load commit diff: ${J instanceof Error?J.message:String(J)}`})}}async selectCompareCommit($){let J=this._compareState.compareDiff;if(!J||$<0||$>=J.commits.length){this.updateCompareSelectionState({type:null,index:0,diff:null});return}let K=J.commits[$];this.updateCompareSelectionState({type:"commit",index:$,diff:null});try{await this.queue.enqueue(async()=>{let Z=await Q8(this.repoPath,K.hash);this.updateCompareSelectionState({diff:Z})})}catch(Z){this.updateState({error:`Failed to load commit diff: ${Z instanceof Error?Z.message:String(Z)}`})}}selectCompareFile($){let J=this._compareState.compareDiff;if(!J||$<0||$>=J.files.length){this.updateCompareSelectionState({type:null,index:0,diff:null});return}let K=J.files[$];this.updateCompareSelectionState({type:"file",index:$,diff:K.diff})}}var H7=new Map;function p9($){let J=H7.get($);if(!J)J=new u9($),H7.set($,J);return J}function z8($){let J=H7.get($);if(J)J.dispose(),H7.delete($)}class q8{screen;layout;uiState;gitManager=null;followMode=null;explorerManager=null;config;commandServer;repoPath;currentTheme;commitFlowState;commitTextarea=null;activeModal=null;bottomPaneTotalRows=0;pendingSelectionAnchor=null;constructor($){this.config=$.config,this.commandServer=$.commandServer??null,this.repoPath=$.initialPath??process.cwd(),this.currentTheme=$.config.theme,this.uiState=new e7({splitRatio:$.config.splitRatio??0.4}),this.screen=g9.screen({smartCSR:!0,fullUnicode:!0,title:"diffstalker",mouse:!0,terminal:"xterm-256color"});let J=this.screen;if(J.tput)J.tput.colors=256;if(J.program?.tput)J.program.tput.colors=256;if(this.layout=new v7(this.screen,this.uiState.state.splitRatio),this.screen.on("resize",()=>{setImmediate(()=>this.render())}),this.commitFlowState=new t7({getHeadMessage:()=>this.gitManager?.getHeadCommitMessage()??Promise.resolve(""),onCommit:async(K,Z)=>{await this.gitManager?.commit(K,Z)},onSuccess:()=>{this.uiState.setTab("diff"),this.render()}}),this.commitTextarea=g9.textarea({parent:this.layout.bottomPane,top:3,left:1,width:"100%-4",height:1,inputOnFocus:!0,hidden:!0,style:{fg:"white",bg:"default"}}),this.commitTextarea.on("submit",()=>{this.commitFlowState.submit()}),this.commitTextarea.on("keypress",()=>{setImmediate(()=>{let K=this.commitTextarea?.getValue()??"";this.commitFlowState.setMessage(K)})}),this.setupKeyboardHandlers(),this.setupMouseEventHandlers(),this.setupStateListeners(),this.config.watcherEnabled)this.followMode=new k7(this.config.targetFile,()=>this.repoPath,{onRepoChange:(K,Z)=>this.handleFollowRepoChange(K,Z),onFileNavigate:(K)=>this.handleFollowFileNavigate(K)}),this.followMode.start();if(this.commandServer)this.setupCommandHandler();this.initGitManager(),this.render()}setupKeyboardHandlers(){j8(this.screen,{exit:()=>this.exit(),navigateDown:()=>this.navigateDown(),navigateUp:()=>this.navigateUp(),stageSelected:()=>this.stageSelected(),unstageSelected:()=>this.unstageSelected(),stageAll:()=>this.stageAll(),unstageAll:()=>this.unstageAll(),toggleSelected:()=>this.toggleSelected(),enterExplorerDirectory:()=>this.enterExplorerDirectory(),goExplorerUp:()=>this.goExplorerUp(),openFileFinder:()=>this.openFileFinder(),focusCommitInput:()=>this.focusCommitInput(),unfocusCommitInput:()=>this.unfocusCommitInput(),refresh:()=>this.refresh(),toggleMouseMode:()=>this.toggleMouseMode(),toggleFollow:()=>this.toggleFollow(),showDiscardConfirm:($)=>this.showDiscardConfirm($),render:()=>this.render()},{hasActiveModal:()=>this.activeModal!==null,getBottomTab:()=>this.uiState.state.bottomTab,getCurrentPane:()=>this.uiState.state.currentPane,isCommitInputFocused:()=>this.commitFlowState.state.inputFocused,getStatusFiles:()=>this.gitManager?.state.status?.files??[],getSelectedIndex:()=>this.uiState.state.selectedIndex,uiState:this.uiState,explorerManager:this.explorerManager,commitFlowState:this.commitFlowState,gitManager:this.gitManager,layout:this.layout})}setupMouseEventHandlers(){$9(this.layout,{selectHistoryCommitByIndex:($)=>this.selectHistoryCommitByIndex($),selectCompareItem:($)=>this.selectCompareItem($),selectFileByIndex:($)=>this.selectFileByIndex($),toggleFileByIndex:($)=>this.toggleFileByIndex($),toggleMouseMode:()=>this.toggleMouseMode(),toggleFollow:()=>this.toggleFollow(),render:()=>this.render()},{uiState:this.uiState,explorerManager:this.explorerManager,getStatusFiles:()=>this.gitManager?.state.status?.files??[],getHistoryCommitCount:()=>this.gitManager?.historyState.commits.length??0,getCompareCommits:()=>this.gitManager?.compareState?.compareDiff?.commits??[],getCompareFiles:()=>this.gitManager?.compareState?.compareDiff?.files??[],getBottomPaneTotalRows:()=>this.bottomPaneTotalRows,getScreenWidth:()=>this.screen.width||80})}async toggleFileByIndex($){let J=this.gitManager?.state.status?.files??[],K=b(J,$);if(K)if(this.pendingSelectionAnchor=n(J,this.uiState.state.selectedIndex),K.staged)await this.gitManager?.unstage(K);else await this.gitManager?.stage(K)}setupStateListeners(){this.uiState.on("change",()=>{this.render()}),this.uiState.on("tab-change",(J)=>{if(J==="history")this.gitManager?.loadHistory();else if(J==="compare")this.gitManager?.refreshCompareDiff(this.uiState.state.includeUncommitted);else if(J==="explorer"){if(!this.explorerManager?.state.displayRows.length)this.explorerManager?.loadDirectory("")}}),this.uiState.on("modal-change",(J)=>{if(this.activeModal)this.activeModal=null;if(J==="theme")this.activeModal=new r7(this.screen,this.currentTheme,(K)=>{this.currentTheme=K,h7({theme:K}),this.activeModal=null,this.uiState.closeModal(),this.render()},()=>{this.activeModal=null,this.uiState.closeModal()}),this.activeModal.focus();else if(J==="hotkeys")this.activeModal=new a7(this.screen,()=>{this.activeModal=null,this.uiState.closeModal()}),this.activeModal.focus();else if(J==="baseBranch")this.gitManager?.getCandidateBaseBranches().then((K)=>{let Z=this.gitManager?.compareState.compareBaseBranch??null;this.activeModal=new s7(this.screen,K,Z,(X)=>{this.activeModal=null,this.uiState.closeModal();let Q=this.uiState.state.includeUncommitted;this.gitManager?.setCompareBaseBranch(X,Q)},()=>{this.activeModal=null,this.uiState.closeModal()}),this.activeModal.focus()})});let $=null;this.uiState.on("change",(J)=>{if($)clearTimeout($);$=setTimeout(()=>{if(J.splitRatio!==this.config.splitRatio)h7({splitRatio:J.splitRatio})},500)})}handleFollowRepoChange($,J){let K=this.repoPath;this.repoPath=$,this.initGitManager(K),this.resetRepoSpecificState(),this.loadCurrentTabData(),this.render()}handleFollowFileNavigate($){this.navigateToFile($),this.render()}initGitManager($){if(this.gitManager)this.gitManager.removeAllListeners(),z8($??this.repoPath);this.gitManager=p9(this.repoPath),this.gitManager.on("state-change",()=>{let J=this.gitManager?.state.status?.files??[];if(this.pendingSelectionAnchor){let K=this.pendingSelectionAnchor;this.pendingSelectionAnchor=null;let Z=Y8(J,K.category,K.categoryIndex);this.uiState.setSelectedIndex(Z),this.selectFileByIndex(Z)}else if(J.length>0){let K=J.length-1;if(this.uiState.state.selectedIndex>K)this.uiState.setSelectedIndex(K)}this.updateExplorerGitStatus(),this.render()}),this.gitManager.on("history-state-change",(J)=>{if(J.commits.length>0&&!J.selectedCommit){let K=this.uiState.state;if(K.bottomTab==="history")this.selectHistoryCommitByIndex(K.historySelectedIndex)}this.render()}),this.gitManager.on("compare-state-change",()=>{this.render()}),this.gitManager.on("compare-selection-change",()=>{this.render()}),this.gitManager.startWatching(),this.gitManager.refresh(),this.initExplorerManager()}initExplorerManager(){if(this.explorerManager)this.explorerManager.dispose();let $={hideHidden:!0,hideGitignored:!0,showOnlyChanges:!1};this.explorerManager=new o7(this.repoPath,$),this.explorerManager.on("state-change",()=>{this.render()}),this.explorerManager.loadDirectory(""),this.updateExplorerGitStatus()}updateExplorerGitStatus(){if(!this.explorerManager||!this.gitManager)return;let $=this.gitManager.state.status?.files??[],J={files:new Map,directories:new Set};for(let K of $){J.files.set(K.path,{status:K.status,staged:K.staged});let Z=K.path.split("/"),X="";for(let Q=0;Q<Z.length-1;Q++)X=X?`${X}/${Z[Q]}`:Z[Q],J.directories.add(X);J.directories.add("")}this.explorerManager.setGitStatus(J)}resetRepoSpecificState(){this.compareSelection=null,this.uiState.resetForNewRepo()}loadCurrentTabData(){let $=this.uiState.state.bottomTab;if($==="history")this.gitManager?.loadHistory();else if($==="compare")this.gitManager?.refreshCompareDiff(this.uiState.state.includeUncommitted)}setupCommandHandler(){if(!this.commandServer)return;let $={navigateUp:()=>this.navigateUp(),navigateDown:()=>this.navigateDown(),switchTab:(J)=>this.uiState.setTab(J),togglePane:()=>this.uiState.togglePane(),stage:async()=>this.stageSelected(),unstage:async()=>this.unstageSelected(),stageAll:async()=>this.stageAll(),unstageAll:async()=>this.unstageAll(),commit:async(J)=>this.commit(J),refresh:async()=>this.refresh(),getState:()=>this.getAppState(),quit:()=>this.exit()};this.commandServer.setHandler($),this.commandServer.notifyReady()}getAppState(){let $=this.uiState.state,J=this.gitManager?.state,K=this.gitManager?.historyState,Z=J?.status?.files??[],X=K?.commits??[];return{currentTab:$.bottomTab,currentPane:$.currentPane,selectedIndex:$.selectedIndex,totalFiles:Z.length,stagedCount:Z.filter((Q)=>Q.staged).length,files:Z.map((Q)=>({path:Q.path,status:Q.status,staged:Q.staged})),historySelectedIndex:$.historySelectedIndex,historyCommitCount:X.length,compareSelectedIndex:$.compareSelectedIndex,compareTotalItems:0,includeUncommitted:$.includeUncommitted,explorerPath:this.repoPath,explorerSelectedIndex:$.explorerSelectedIndex,explorerItemCount:0,wrapMode:$.wrapMode,mouseEnabled:$.mouseEnabled,autoTabEnabled:$.autoTabEnabled}}navigateUp(){let $=this.uiState.state;if($.bottomTab==="history"){if($.currentPane==="history")this.navigateHistoryUp();else if($.currentPane==="diff")this.uiState.setDiffScrollOffset(Math.max(0,$.diffScrollOffset-3));return}if($.bottomTab==="compare"){if($.currentPane==="compare")this.navigateCompareUp();else if($.currentPane==="diff")this.uiState.setDiffScrollOffset(Math.max(0,$.diffScrollOffset-3));return}if($.bottomTab==="explorer"){if($.currentPane==="explorer")this.navigateExplorerUp();else if($.currentPane==="diff")this.uiState.setExplorerFileScrollOffset(Math.max(0,$.explorerFileScrollOffset-3));return}if($.currentPane==="files"){let J=this.gitManager?.state.status?.files??[],K=Math.max(0,$.selectedIndex-1);this.uiState.setSelectedIndex(K),this.selectFileByIndex(K);let Z=T7(K,J);if(Z<$.fileListScrollOffset)this.uiState.setFileListScrollOffset(Z)}else if($.currentPane==="diff")this.uiState.setDiffScrollOffset(Math.max(0,$.diffScrollOffset-3))}navigateDown(){let $=this.uiState.state,J=this.gitManager?.state.status?.files??[];if($.bottomTab==="history"){if($.currentPane==="history")this.navigateHistoryDown();else if($.currentPane==="diff")this.uiState.setDiffScrollOffset($.diffScrollOffset+3);return}if($.bottomTab==="compare"){if($.currentPane==="compare")this.navigateCompareDown();else if($.currentPane==="diff")this.uiState.setDiffScrollOffset($.diffScrollOffset+3);return}if($.bottomTab==="explorer"){if($.currentPane==="explorer")this.navigateExplorerDown();else if($.currentPane==="diff")this.uiState.setExplorerFileScrollOffset($.explorerFileScrollOffset+3);return}if($.currentPane==="files"){let K=Math.min(J.length-1,$.selectedIndex+1);this.uiState.setSelectedIndex(K),this.selectFileByIndex(K);let Z=T7(K,J),X=$.fileListScrollOffset+this.layout.dimensions.topPaneHeight-1;if(Z>=X)this.uiState.setFileListScrollOffset($.fileListScrollOffset+(Z-X+1))}else if($.currentPane==="diff")this.uiState.setDiffScrollOffset($.diffScrollOffset+3)}navigateHistoryUp(){let $=this.uiState.state,J=Math.max(0,$.historySelectedIndex-1);if(J!==$.historySelectedIndex){if(this.uiState.setHistorySelectedIndex(J),J<$.historyScrollOffset)this.uiState.setHistoryScrollOffset(J);this.selectHistoryCommitByIndex(J)}}navigateHistoryDown(){let $=this.uiState.state,J=this.gitManager?.historyState.commits??[],K=Math.min(J.length-1,$.historySelectedIndex+1);if(K!==$.historySelectedIndex){this.uiState.setHistorySelectedIndex(K);let Z=$.historyScrollOffset+this.layout.dimensions.topPaneHeight-1;if(K>=Z)this.uiState.setHistoryScrollOffset($.historyScrollOffset+1);this.selectHistoryCommitByIndex(K)}}selectHistoryCommitByIndex($){let J=this.gitManager?.historyState.commits??[],K=O8(J,$);if(K)this.uiState.setDiffScrollOffset(0),this.gitManager?.selectHistoryCommit(K)}compareSelection=null;navigateCompareUp(){let $=this.gitManager?.compareState,J=$?.compareDiff?.commits??[],K=$?.compareDiff?.files??[];if(J.length===0&&K.length===0)return;let Z=R7(this.compareSelection,J,K,"up");if(Z&&(Z.type!==this.compareSelection?.type||Z.index!==this.compareSelection?.index)){this.selectCompareItem(Z);let X=this.uiState.state,Q=Q7(Z,J,K);if(Q<X.compareScrollOffset)this.uiState.setCompareScrollOffset(Q)}}navigateCompareDown(){let $=this.gitManager?.compareState,J=$?.compareDiff?.commits??[],K=$?.compareDiff?.files??[];if(J.length===0&&K.length===0)return;if(!this.compareSelection){if(J.length>0)this.selectCompareItem({type:"commit",index:0});else if(K.length>0)this.selectCompareItem({type:"file",index:0});return}let Z=R7(this.compareSelection,J,K,"down");if(Z&&(Z.type!==this.compareSelection?.type||Z.index!==this.compareSelection?.index)){this.selectCompareItem(Z);let X=this.uiState.state,Q=Q7(Z,J,K),z=X.compareScrollOffset+this.layout.dimensions.topPaneHeight-1;if(Q>=z)this.uiState.setCompareScrollOffset(X.compareScrollOffset+(Q-z+1))}}selectCompareItem($){if(this.compareSelection=$,this.uiState.setDiffScrollOffset(0),$.type==="commit")this.gitManager?.selectCompareCommit($.index);else this.gitManager?.selectCompareFile($.index)}navigateExplorerUp(){let $=this.uiState.state;if((this.explorerManager?.state.displayRows??[]).length===0)return;let K=this.explorerManager?.navigateUp($.explorerScrollOffset);if(K!==null&&K!==void 0)this.uiState.setExplorerScrollOffset(K);this.uiState.setExplorerSelectedIndex(this.explorerManager?.state.selectedIndex??0)}navigateExplorerDown(){let $=this.uiState.state;if((this.explorerManager?.state.displayRows??[]).length===0)return;let K=this.layout.dimensions.topPaneHeight,Z=this.explorerManager?.navigateDown($.explorerScrollOffset,K);if(Z!==null&&Z!==void 0)this.uiState.setExplorerScrollOffset(Z);this.uiState.setExplorerSelectedIndex(this.explorerManager?.state.selectedIndex??0)}async enterExplorerDirectory(){await this.explorerManager?.enterDirectory(),this.uiState.setExplorerFileScrollOffset(0),this.uiState.setExplorerSelectedIndex(this.explorerManager?.state.selectedIndex??0)}async goExplorerUp(){await this.explorerManager?.goUp(),this.uiState.setExplorerFileScrollOffset(0),this.uiState.setExplorerSelectedIndex(this.explorerManager?.state.selectedIndex??0)}selectFileByIndex($){let J=this.gitManager?.state.status?.files??[],K=b(J,$);if(K)this.uiState.setDiffScrollOffset(0),this.gitManager?.selectFile(K)}navigateToFile($){if(!$||!this.repoPath)return;let J=this.repoPath.endsWith("/")?this.repoPath:this.repoPath+"/";if(!$.startsWith(J))return;let K=$.slice(J.length);if(!K)return;let X=(this.gitManager?.state.status?.files??[]).findIndex((Q)=>Q.path===K);if(X>=0)this.uiState.setSelectedIndex(X),this.selectFileByIndex(X)}async stageSelected(){let $=this.gitManager?.state.status?.files??[],J=this.uiState.state.selectedIndex,K=b($,J);if(K&&!K.staged)this.pendingSelectionAnchor=n($,J),await this.gitManager?.stage(K)}async unstageSelected(){let $=this.gitManager?.state.status?.files??[],J=this.uiState.state.selectedIndex,K=b($,J);if(K?.staged)this.pendingSelectionAnchor=n($,J),await this.gitManager?.unstage(K)}async toggleSelected(){let $=this.gitManager?.state.status?.files??[],J=this.uiState.state.selectedIndex,K=b($,J);if(K)if(this.pendingSelectionAnchor=n($,J),K.staged)await this.gitManager?.unstage(K);else await this.gitManager?.stage(K)}async stageAll(){await this.gitManager?.stageAll()}async unstageAll(){await this.gitManager?.unstageAll()}showDiscardConfirm($){this.activeModal=new n7(this.screen,$.path,async()=>{this.activeModal=null,await this.gitManager?.discard($)},()=>{this.activeModal=null}),this.activeModal.focus()}async openFileFinder(){let $=await this.explorerManager?.getAllFilePaths()??[];if($.length===0)return;this.activeModal=new i7(this.screen,$,async(J)=>{if(this.activeModal=null,await this.explorerManager?.navigateToPath(J))this.uiState.setExplorerScrollOffset(0),this.uiState.setExplorerFileScrollOffset(0);this.render()},()=>{this.activeModal=null,this.render()}),this.activeModal.focus()}async commit($){await this.gitManager?.commit($)}async refresh(){await this.gitManager?.refresh()}toggleMouseMode(){let $=!this.uiState.state.mouseEnabled;this.uiState.toggleMouse();let J=this.screen.program;if($)J.enableMouse();else J.disableMouse()}toggleFollow(){if(!this.followMode)this.followMode=new k7(this.config.targetFile,()=>this.repoPath,{onRepoChange:($,J)=>this.handleFollowRepoChange($,J),onFileNavigate:($)=>this.handleFollowFileNavigate($)});this.followMode.toggle(),this.render()}focusCommitInput(){if(this.commitTextarea)this.commitTextarea.show(),this.commitTextarea.focus(),this.commitTextarea.setValue(this.commitFlowState.state.message),this.commitFlowState.setInputFocused(!0),this.render()}unfocusCommitInput(){if(this.commitTextarea){let $=this.commitTextarea.getValue()??"";this.commitFlowState.setMessage($),this.commitTextarea.hide(),this.commitFlowState.setInputFocused(!1),this.screen.focusPush(this.layout.bottomPane),this.render()}}render(){this.updateHeader(),this.updateTopPane(),this.updateBottomPane(),this.updateFooter(),this.screen.render()}updateHeader(){let $=this.gitManager?.state,J=this.screen.width||80,K=z9(this.repoPath,$?.status?.branch??null,$?.isLoading??!1,$?.error??null,J);this.layout.headerBox.setContent(K)}updateTopPane(){let $=this.uiState.state,J=this.screen.width||80,K=n8($,this.gitManager?.state.status?.files??[],this.gitManager?.historyState?.commits??[],this.gitManager?.compareState?.compareDiff??null,this.compareSelection,this.explorerManager?.state,J,this.layout.dimensions.topPaneHeight);this.layout.topPane.setContent(K)}updateBottomPane(){let $=this.uiState.state,J=this.screen.width||80,Z=(this.gitManager?.state.status?.files??[]).filter((z)=>z.staged).length;this.commitFlowState.setStagedCount(Z);let{content:X,totalRows:Q}=i8($,this.gitManager?.state.diff??null,this.gitManager?.historyState,this.gitManager?.compareSelectionState,this.explorerManager?.state?.selectedFile??null,this.commitFlowState.state,Z,this.currentTheme,J,this.layout.dimensions.bottomPaneHeight);if(this.bottomPaneTotalRows=Q,this.layout.bottomPane.setContent(X),this.commitTextarea)if($.bottomTab==="commit"&&this.commitFlowState.state.inputFocused)this.commitTextarea.show();else this.commitTextarea.hide()}updateFooter(){let $=this.uiState.state,J=this.screen.width||80,K=V9($.bottomTab,$.mouseEnabled,$.autoTabEnabled,$.wrapMode,this.followMode?.isEnabled??!1,this.explorerManager?.showOnlyChanges??!1,J);this.layout.footerBox.setContent(K)}exit(){if(this.gitManager)z8(this.repoPath);if(this.explorerManager)this.explorerManager.dispose();if(this.followMode)this.followMode.stop();if(this.commandServer)this.commandServer.stop();this.screen.destroy()}start(){return new Promise(($)=>{this.screen.on("destroy",()=>{$()})})}}import*as m9 from"net";import*as g from"fs";import{EventEmitter as r$}from"events";class V8 extends r${server=null;socketPath;handler=null;ready=!1;constructor($){super();this.socketPath=$}setHandler($){this.handler=$}notifyReady(){this.ready=!0,this.emit("ready")}isReady(){return this.ready&&this.handler!==null}async start(){if(g.existsSync(this.socketPath))g.unlinkSync(this.socketPath);return new Promise(($,J)=>{this.server=m9.createServer((K)=>{this.handleConnection(K)}),this.server.on("error",(K)=>{J(K)}),this.server.listen(this.socketPath,()=>{g.chmodSync(this.socketPath,384),$()})})}stop(){if(this.server)this.server.close(),this.server=null;if(g.existsSync(this.socketPath))g.unlinkSync(this.socketPath)}handleConnection($){let J="";$.on("data",async(K)=>{J+=K.toString();let Z=J.split(`
|
|
56
|
+
`);J=Z.pop()||"";for(let X of Z)if(X.trim()){let Q=await this.processCommand(X);$.write(JSON.stringify(Q)+`
|
|
57
|
+
`)}}),$.on("error",(K)=>{this.emit("error",K)})}async processCommand($){try{let J=JSON.parse($);if(J.action==="ping")return{success:!0,ready:this.isReady()};if(!this.handler)return{success:!1,error:"No handler registered"};switch(J.action){case"navigateUp":return this.handler.navigateUp(),{success:!0};case"navigateDown":return this.handler.navigateDown(),{success:!0};case"switchTab":return this.handler.switchTab(J.tab),{success:!0};case"togglePane":return this.handler.togglePane(),{success:!0};case"stage":return await this.handler.stage(),{success:!0};case"unstage":return await this.handler.unstage(),{success:!0};case"stageAll":return await this.handler.stageAll(),{success:!0};case"unstageAll":return await this.handler.unstageAll(),{success:!0};case"commit":return await this.handler.commit(J.message),{success:!0};case"refresh":return await this.handler.refresh(),{success:!0};case"getState":return{success:!0,state:this.handler.getState()};case"quit":return this.handler.quit(),{success:!0};default:return{success:!1,error:`Unknown action: ${J.action}`}}}catch(J){return{success:!1,error:J instanceof Error?J.message:String(J)}}}}function c(){process.stdout.write("\x1B[?1006l"),process.stdout.write("\x1B[?1002l"),process.stdout.write("\x1B[?1000l"),process.stdout.write("\x1B[?1003l"),process.stdout.write("\x1B[?25h")}c();process.on("exit",c);process.on("SIGINT",()=>{c(),process.exit(0)});process.on("SIGTERM",()=>{c(),process.exit(0)});process.on("uncaughtException",($)=>{c(),console.error("Uncaught exception:",$),process.exit(1)});process.on("unhandledRejection",($)=>{c(),console.error("Unhandled rejection:",$),process.exit(1)});function a$($){let J={};for(let K=0;K<$.length;K++){let Z=$[K];if(Z==="--follow"||Z==="-f"){if(J.follow=!0,$[K+1]&&!$[K+1].startsWith("-"))J.followFile=$[++K]}else if(Z==="--once")J.once=!0;else if(Z==="--debug"||Z==="-d")J.debug=!0;else if(Z==="--socket"||Z==="-s")if($[K+1]&&!$[K+1].startsWith("-"))J.socket=$[++K];else console.error("Error: --socket requires a path argument"),process.exit(1);else if(Z==="--help"||Z==="-h")console.log(`
|
|
43
58
|
diffstalker - Terminal git diff/status viewer
|
|
44
59
|
|
|
45
60
|
Usage: diffstalker [options] [path]
|
|
@@ -47,6 +62,7 @@ Usage: diffstalker [options] [path]
|
|
|
47
62
|
Options:
|
|
48
63
|
-f, --follow [FILE] Follow hook file for dynamic repo switching
|
|
49
64
|
(default: ~/.cache/diffstalker/target)
|
|
65
|
+
-s, --socket PATH Enable IPC server on Unix socket for testing
|
|
50
66
|
--once Show status once and exit
|
|
51
67
|
-d, --debug Log path changes to stderr for debugging
|
|
52
68
|
-h, --help Show this help message
|
|
@@ -64,20 +80,19 @@ Environment:
|
|
|
64
80
|
DIFFSTALKER_PAGER External pager for diff display
|
|
65
81
|
|
|
66
82
|
Keyboard:
|
|
67
|
-
j/k,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
Enter/Space
|
|
73
|
-
Tab
|
|
74
|
-
1/2
|
|
75
|
-
c
|
|
76
|
-
r
|
|
77
|
-
q / Ctrl+C
|
|
83
|
+
j/k, Up/Down Navigate files / scroll diff
|
|
84
|
+
s Stage selected file
|
|
85
|
+
Shift+u Unstage selected file
|
|
86
|
+
Shift+a Stage all files
|
|
87
|
+
Shift+z Unstage all files
|
|
88
|
+
Enter/Space Toggle stage/unstage
|
|
89
|
+
Tab Switch between panes
|
|
90
|
+
1/2/3/4/5 Switch tabs (Diff/Commit/History/Compare/Explorer)
|
|
91
|
+
c Open commit panel
|
|
92
|
+
r Refresh
|
|
93
|
+
q / Ctrl+C Quit
|
|
78
94
|
|
|
79
95
|
Mouse:
|
|
80
|
-
Click
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
`),process.exit(0);else if(!J.startsWith("-"))Y.initialPath=J}return Y}var r8=uJ(process.argv.slice(2)),RX=mY();if(r8.follow){if(RX.watcherEnabled=!0,r8.followFile)RX.targetFile=r8.followFile}if(r8.debug)RX.debug=!0;var{waitUntilExit:hJ}=pJ(xJ(g9,{config:RX,initialPath:r8.initialPath}));hJ().then(()=>{process.exit(0)});
|
|
96
|
+
Click Select file / focus pane
|
|
97
|
+
Scroll Navigate files / scroll diff
|
|
98
|
+
`),process.exit(0);else if(!Z.startsWith("-"))J.initialPath=Z}return J}async function s$(){let $=a$(process.argv.slice(2)),J=J9();if($.follow){if(J.watcherEnabled=!0,$.followFile)J.targetFile=$.followFile}if($.debug)J.debug=!0;let K=null;if($.socket){K=new V8($.socket);try{await K.start()}catch(X){console.error("Failed to start command server:",X),process.exit(1)}}if(await new q8({config:J,initialPath:$.initialPath,commandServer:K}).start(),K)K.stop();process.exit(0)}s$().catch(($)=>{console.error("Fatal error:",$),c(),process.exit(1)});
|