diffstalker 0.2.2 → 0.2.3
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/dist/App.js +118 -3
- package/dist/KeyBindings.js +75 -1
- package/dist/MouseHandlers.js +13 -2
- package/dist/core/ExplorerStateManager.js +21 -38
- package/dist/core/GitStateManager.js +142 -1
- package/dist/git/status.js +95 -0
- package/dist/index.js +55 -50
- package/dist/types/remote.js +5 -0
- package/dist/ui/PaneRenderers.js +14 -4
- package/dist/ui/modals/BranchPicker.js +157 -0
- package/dist/ui/modals/CommitActionConfirm.js +66 -0
- package/dist/ui/modals/FileFinder.js +30 -21
- package/dist/ui/modals/HotkeysModal.js +23 -0
- package/dist/ui/modals/SoftResetConfirm.js +68 -0
- package/dist/ui/modals/StashListModal.js +98 -0
- package/dist/ui/widgets/CommitPanel.js +113 -7
- package/dist/ui/widgets/Header.js +37 -3
- package/metrics/v0.2.3.json +243 -0
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -1,66 +1,71 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
`)}function
|
|
4
|
-
`)}function
|
|
5
|
-
`)}function
|
|
6
|
-
`)}function
|
|
7
|
-
`)}function
|
|
2
|
+
import x5 from"neo-blessed";import J$ from"neo-blessed";var p$=0.05;function u5($,J,K,Z=1){let X=Z+4,Q=$-X,q=Math.floor(Q*K),z=Q-q;return{width:J,height:$,headerHeight:Z,topPaneHeight:q,bottomPaneHeight:z,footerRow:$-1}}function m5($,J,K,Z){let X=J+1,Q=X+K,q=Q+1,z=q+Z,V=$-1;return{stagingPaneStart:X,fileListEnd:Q,diffPaneStart:q,diffPaneEnd:z,footerRow:V}}class g${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 u5($,J,this._splitRatio)}createHeaderBox(){return J$.box({parent:this.screen,top:0,left:0,width:"100%",height:this._dimensions.headerHeight,tags:!0})}createSeparator($){let J=this.screen.width||80;return J$.box({parent:this.screen,top:$,left:0,width:"100%",height:1,content:"─".repeat(J),style:{fg:"gray"}})}createTopPane(){return J$.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 J$.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 J$.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 m5(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 K$($){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 a($,J){let{modified:K,untracked:Z}=K$($),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:q}=K$($);if(q.length===0)return 0;let V={modified:Z,untracked:X,staged:Q}[J];if(V.length===0)return q.length-1;let Y=Math.min(K,V.length-1);return{modified:0,untracked:Z.length,staged:Z.length+X.length}[J]+Y}function u$($,J){if($.length<=J)return $;let Z=Math.max(J,20);if($.length<=Z)return $;let X=$.split("/");if(X.length===1){let j=Math.floor((Z-1)/2);return $.slice(0,j)+"…"+$.slice(-(Z-j-1))}let Q=X[X.length-1],q=X[0],z="/…/";if(q.length+z.length+Q.length>Z){let j=Z-2;if(Q.length>j){let B=Math.floor((j-1)/2);return"…/"+Q.slice(0,B)+"…"+Q.slice(-(j-B-1))}return"…/"+Q}let Y=q,U=1;while(U<X.length-1){let j=X[U],B=Y+"/"+j;if(B.length+z.length+Q.length<=Z)Y=B,U++;else break}if(U===X.length-1)return $;return Y+z+Q}function z$($){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 V$($){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 Y$($,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 U$($,J){if($&&J)return"{cyan-fg}{bold}▸ {/bold}{/cyan-fg}";else if($)return"{gray-fg}▸ {/gray-fg}";return" "}function B$($,J,K,Z){let X=u$($,Z);if(J&&K)return`{cyan-fg}{inverse}${X}{/inverse}{/cyan-fg}`;else if(J)return`{cyan-fg}${X}{/cyan-fg}`;return X}function G$($){if(!$)return"";return` {gray-fg}← ${u$($,30)}{/gray-fg}`}function j$($){let{modified:J,untracked:K,staged:Z}=K$($),X=[],Q=0;if(J.length>0)X.push({type:"header",content:"Modified:",headerColor:"yellow"}),J.forEach((q)=>{X.push({type:"file",file:q,fileIndex:Q++})});if(K.length>0){if(J.length>0)X.push({type:"spacer"});X.push({type:"header",content:"Untracked:",headerColor:"gray"}),K.forEach((q)=>{X.push({type:"file",file:q,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((q)=>{X.push({type:"file",file:q,fileIndex:Q++})})}return X}function f5($,J){if(!J)return"";let K=J.staged.get($.path)??0,Z=J.unstaged.get($.path)??0,X=K+Z;if(X===0)return"";let Q=$.staged?K:Z;if(Q===X)return` {cyan-fg}@${X}{/cyan-fg}`;return` {cyan-fg}@${Q}/${X}{/cyan-fg}`}function h5($,J,K,Z,X,Q){let q=J===K,z=z$($.status),V=V$($.status),Y=$.staged?"[-]":"[+]",U=$.staged?"red":"green",j=Y$($.insertions,$.deletions),B=f5($,Q),G=j.replace(/\{[^}]+\}/g,"").length,M=B.replace(/\{[^}]+\}/g,"").length,v=X-G-M,W=U$(q,Z);return W+=`{${U}-fg}${Y}{/${U}-fg} `,W+=`{${V}-fg}${z}{/${V}-fg} `,W+=B$($.path,q,Z,v),W+=G$($.originalPath),W+=j,W+=B,W}function C8($,J,K,Z,X=0,Q,q){if($.length===0)return"{gray-fg} No changes{/gray-fg}";let z=j$($),V=Z-12,Y=Q?z.slice(X,X+Q):z.slice(X),U=[],j=!1;for(let B of Y)switch(B.type){case"header":{let G=`{bold}{${B.headerColor}-fg}${B.content}{/${B.headerColor}-fg}{/bold}`;if(!j)j=!0,G+=" {gray-fg}(h:flat){/gray-fg}";U.push(G);break}case"spacer":U.push("");break;case"file":if(B.file&&B.fileIndex!==void 0)U.push(h5(B.file,B.fileIndex,J,K,V,q??null));break}return U.join(`
|
|
3
|
+
`)}function P8($){return j$($).length}function b($,J){let{ordered:K}=K$($);return K[J]??null}function S8($,J){let Z=j$(J)[$];if(Z?.type==="file"&&Z.fileIndex!==void 0)return Z.fileIndex;return null}function b8($,J){let K=j$(J);for(let Z=0;Z<K.length;Z++)if(K[Z].type==="file"&&K[Z].fileIndex===$)return Z;return 0}function _$($,J){let K=new Map;for(let X of $){let Q=K.get(X.path)??{staged:null,unstaged:null};if(X.staged)Q.staged=X;else Q.unstaged=X;K.set(X.path,Q)}let Z=[];for(let[X,{staged:Q,unstaged:q}]of K){let z=J?.staged.get(X)??0,V=J?.unstaged.get(X)??0,Y=z+V,U;if(Q&&q)U="partial";else if(Q)U="staged";else U="unstaged";let j=q??Q,B,G;if(Q?.insertions!==void 0||q?.insertions!==void 0)B=(Q?.insertions??0)+(q?.insertions??0);if(Q?.deletions!==void 0||q?.deletions!==void 0)G=(Q?.deletions??0)+(q?.deletions??0);Z.push({path:X,status:j.status,stagingState:U,stagedHunks:z,totalHunks:Y,insertions:B,deletions:G,originalPath:j.originalPath,stagedEntry:Q,unstagedEntry:q})}return Z.sort((X,Q)=>X.path.localeCompare(Q.path)),Z}function w($,J){return $[J]??null}function w8($,J){return $.findIndex((K)=>K.path===J)}function x8($,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;if(K.getBottomTab()==="diff"&&K.getCurrentPane()==="diff")J.toggleCurrentHunk();else 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.getExplorerManager()?.toggleShowOnlyChanges()}),$.key(["/"],()=>{if(K.hasActiveModal())return;if(K.getBottomTab()==="explorer")J.openFileFinder()}),$.key(["C-p"],()=>{if(K.hasActiveModal())return;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(["C-a"],()=>{if(K.getBottomTab()==="commit")K.commitFlowState.toggleAmend(),J.render()}),$.key(["S-p"],()=>{if(K.hasActiveModal()||K.isCommitInputFocused()||K.isRemoteInProgress())return;J.push()}),$.key(["S-f"],()=>{if(K.hasActiveModal()||K.isCommitInputFocused()||K.isRemoteInProgress())return;J.fetchRemote()}),$.key(["S-r"],()=>{if(K.hasActiveModal()||K.isCommitInputFocused()||K.isRemoteInProgress())return;J.pullRebase()}),$.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(-p$),K.layout.setSplitRatio(K.uiState.state.splitRatio),J.render()}),$.key(["=","+","]"],()=>{K.uiState.adjustSplitRatio(p$),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.hasActiveModal()||K.isCommitInputFocused())return;if(K.getBottomTab()==="compare")K.uiState.openModal("baseBranch");else if(K.getBottomTab()==="commit")J.openBranchPicker()}),$.key(["u"],()=>{if(K.hasActiveModal())return;if(K.getBottomTab()==="compare"){K.uiState.toggleIncludeUncommitted();let X=K.uiState.state.includeUncommitted;K.getGitManager()?.refreshCompareDiff(X)}}),$.key(["h"],()=>{if(K.hasActiveModal())return;let X=K.getBottomTab();if(X==="diff"||X==="commit")K.uiState.toggleFlatViewMode()}),$.key(["d"],()=>{if(K.getBottomTab()==="diff")if(K.uiState.state.flatViewMode){let X=w(K.getCachedFlatFiles(),K.getSelectedIndex());if(X?.unstagedEntry){let Q=X.unstagedEntry;if(Q.status!=="untracked")J.showDiscardConfirm(Q)}}else{let X=K.getStatusFiles(),Q=b(X,K.getSelectedIndex());if(Q&&!Q.staged&&Q.status!=="untracked")J.showDiscardConfirm(Q)}}),$.key(["n"],()=>{if(K.hasActiveModal())return;if(K.getBottomTab()==="diff"&&K.getCurrentPane()==="diff")J.navigateNextHunk()}),$.key(["S-n"],()=>{if(K.hasActiveModal())return;if(K.getBottomTab()==="diff"&&K.getCurrentPane()==="diff")J.navigatePrevHunk()}),$.key(["S-s"],()=>{if(K.hasActiveModal()||K.isCommitInputFocused()||K.isRemoteInProgress())return;J.stash()}),$.key(["o"],()=>{if(K.hasActiveModal()||K.isCommitInputFocused())return;if(K.getBottomTab()==="commit")J.stashPop()}),$.key(["l"],()=>{if(K.hasActiveModal()||K.isCommitInputFocused())return;if(K.getBottomTab()==="commit")J.openStashListModal()}),$.key(["S-x"],()=>{if(K.hasActiveModal()||K.isCommitInputFocused()||K.isRemoteInProgress())return;if(K.getBottomTab()==="commit")J.showSoftResetConfirm()}),$.key(["p"],()=>{if(K.hasActiveModal()||K.isCommitInputFocused())return;if(K.getBottomTab()==="history")J.cherryPickSelected()}),$.key(["v"],()=>{if(K.hasActiveModal()||K.isCommitInputFocused())return;if(K.getBottomTab()==="history")J.revertSelected()})}function d5($){switch($){case"unstaged":return{text:"[+]",color:"green"};case"staged":return{text:"[-]",color:"red"};case"partial":return{text:"[~]",color:"yellow"}}}function c5($){if($.totalHunks===0)return"";return` {cyan-fg}@${$.stagedHunks}/${$.totalHunks}{/cyan-fg}`}function l5($,J,K,Z,X){let Q=J===K,q=z$($.status),z=V$($.status),V=d5($.stagingState),Y=Y$($.insertions,$.deletions),U=c5($),j=Y.replace(/\{[^}]+\}/g,"").length,B=U.replace(/\{[^}]+\}/g,"").length,G=X-j-B,M=U$(Q,Z);return M+=`{${V.color}-fg}${V.text}{/${V.color}-fg} `,M+=`{${z}-fg}${q}{/${z}-fg} `,M+=B$($.path,Q,Z,G),M+=G$($.originalPath),M+=Y,M+=U,M}function p8($,J,K,Z,X=0,Q){if($.length===0)return"{gray-fg} No changes{/gray-fg}";let q=Z-12,z=[];z.push("{bold}{gray-fg}All files (h):{/gray-fg}{/bold}");for(let Y=0;Y<$.length;Y++)z.push(l5($[Y],Y,J,K,q));return(Q?z.slice(X,X+Q):z.slice(X)).join(`
|
|
4
|
+
`)}function g8($){if($.length===0)return 0;return $.length+1}function M$($){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 u8($){return $.toLocaleString("en-US",{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}function o5($,J){if($.length<=J)return $;if(J<=3)return $.slice(0,J);return $.slice(0,J-3)+"..."}function O$($,J,K,Z=20){let X=J||"",Q=Math.max(0,K-Z-1),q=X;if(q.length>Q&&Q>3)q=q.slice(0,Q-3)+"...";else if(q.length>Q)q="";let z=q?q.length+1:0,V=Math.max(Z,K-z);return{displayMessage:o5($,V),displayRefs:q}}function m8($,J,K,Z,X=0,Q){if($.length===0)return"{gray-fg}No commits yet{/gray-fg}";let q=Q?$.slice(X,X+Q):$.slice(X),z=[];for(let V=0;V<q.length;V++){let Y=q[V],B=X+V===J&&K,G=M$(Y.date),M=11+G.length+2+2,v=Math.max(10,Z-M),{displayMessage:W,displayRefs:A}=O$(Y.message,Y.refs,v),T="";if(B)T+="{cyan-fg}{bold}▸ {/bold}{/cyan-fg}";else T+=" ";if(T+=`{yellow-fg}${Y.shortHash}{/yellow-fg} `,B)T+=`{cyan-fg}{inverse}${m$(W)}{/inverse}{/cyan-fg}`;else T+=m$(W);if(T+=` {gray-fg}(${G}){/gray-fg}`,A)T+=` {green-fg}${m$(A)}{/green-fg}`;z.push(T)}return z.join(`
|
|
5
|
+
`)}function m$($){return $.replace(/\{/g,"{{").replace(/\}/g,"}}")}function f8($,J){return $[J]??null}function h8($){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 q=0;q<X.length;q++){let z=X[q],V=q===X.length-1,Y=X.slice(0,q+1).join("/"),U=Q.children.find((j)=>j.name===z&&j.isDirectory===!V);if(!U)U={name:z,fullPath:Y,isDirectory:!V,children:[],depth:Q.depth+1,fileIndex:V?K:void 0},Q.children.push(U);Q=U}}return d8(J),l8(J),J}function d8($){for(let J of $.children)d8(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,c8(K,K.depth)}}}function c8($,J){$.depth=J;for(let K of $.children)c8(K,J+1)}function l8($){$.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)l8(J)}function o8($){let J=[];function K(Z,X){for(let Q=0;Q<Z.children.length;Q++){let q=Z.children[Q],z=Q===Z.children.length-1;if(J.push({type:q.isDirectory?"directory":"file",name:q.name,fullPath:q.fullPath,depth:q.depth-1,fileIndex:q.fileIndex,isLast:z,parentIsLast:[...X]}),q.isDirectory)K(q,[...X,z])}}return K($,[]),J}function f$($){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",r5="\x1B[1m",s="\x1B[90m",c$="\x1B[36m",a8="\x1B[33m",d$="\x1B[32m",r8="\x1B[31m",s8="\x1B[34m",h$="\x1B[35m",n8="\x1B[7m";function Z$($,J,K=!0,Z=!0){let X=[];if($.length>0){if(X.push({type:"section-header",sectionType:"commits"}),K)$.forEach((Q,q)=>{X.push({type:"commit",commitIndex:q,commit:Q})})}if(J.length>0){if($.length>0)X.push({type:"spacer"});if(X.push({type:"section-header",sectionType:"files"}),Z){let Q=h8(J),q=o8(Q);for(let z of q)if(z.type==="directory")X.push({type:"directory",treeRow:z});else{let V=J[z.fileIndex];X.push({type:"file",fileIndex:z.fileIndex,file:V,treeRow:z})}}}return X}function a5($,J,K,Z){let X=J&&K,Q=M$($.date),q=13+Q.length+2,z=Math.max(10,Z-q),{displayMessage:V,displayRefs:Y}=O$($.message,$.refs,z),U=` ${a8}${$.shortHash}${L} `;if(X)U+=`${c$}${n8}${V}${L}`;else U+=V;if(U+=` ${s}(${Q})${L}`,Y)U+=` ${d$}${Y}${L}`;return`{escape}${U}{/escape}`}function s5($,J){let K=f$($),Z="▸ ",X=J-K.length-2-2,Q=$.name;if(Q.length>X)Q=Q.slice(0,X-1)+"…";return`{escape}${`${s}${K}${L}${s8}${"▸ "}${Q}${L}`}{/escape}`}function n5($,J,K,Z,X){let Q=K&&Z,q=$.isUncommitted??!1,z=f$(J),V={added:d$,modified:a8,deleted:r8,renamed:s8},Y={added:"+",modified:"●",deleted:"−",renamed:"→"},U=q?h$:V[$.status],j=Y[$.status],B=`(+${$.additions} -${$.deletions})`,G=q?" [uncommitted]":"",M=z.length+2+B.length+G.length+2,v=Math.max(5,X-M),W=J.name;if(W.length>v)W=W.slice(0,v-1)+"…";let A=`${s}${z}${L}`;if(A+=`${U}${j}${L} `,Q)A+=`${c$}${n8}${W}${L}`;else if(q)A+=`${h$}${W}${L}`;else A+=W;if(A+=` ${s}(${d$}+${$.additions}${L} ${r8}-${$.deletions}${s})${L}`,q)A+=` ${h$}[uncommitted]${L}`;return`{escape}${A}{/escape}`}function i5($,J){if(!J)return!1;if($.type==="commit"&&$.commitIndex!==void 0)return J.type==="commit"&&J.index===$.commitIndex;if($.type==="file"&&$.fileIndex!==void 0)return J.type==="file"&&J.index===$.fileIndex;return!1}function t5($,J){return`{escape}${c$}${r5}▼ ${$}${L} ${s}(${J})${L}{/escape}`}function e5($,J,K,Z,X,Q){if($.type==="section-header"){let z=$.sectionType==="commits";return t5(z?"Commits":"Files",z?Z.length:X.length)}if($.type==="spacer")return"";if($.type==="directory"&&$.treeRow)return s5($.treeRow,Q);let q=i5($,J);if($.type==="commit"&&$.commit&&$.commitIndex!==void 0)return a5($.commit,q,K,Q);if($.type==="file"&&$.file&&$.fileIndex!==void 0&&$.treeRow)return n5($.file,$.treeRow,q,K,Q);return null}function i8($,J,K,Z,X,Q=0,q){if($.length===0&&J.length===0)return"{gray-fg}No changes compared to base branch{/gray-fg}";let z=Z$($,J);return(q?z.slice(Q,Q+q):z.slice(Q)).map((U)=>e5(U,K,Z,$,J,X)).filter((U)=>U!==null).join(`
|
|
6
|
+
`)}function t8($,J,K=!0,Z=!0){return Z$($,J,K,Z).length}function l$($,J,K,Z=!0,X=!0){let q=Z$(J,K,Z,X)[$];if(!q)return null;if(q.type==="commit"&&q.commitIndex!==void 0)return{type:"commit",index:q.commitIndex};if(q.type==="file"&&q.fileIndex!==void 0)return{type:"file",index:q.fileIndex};return null}function v$($,J,K,Z=!0,X=!0){let Q=Z$(J,K,Z,X);for(let q=0;q<Q.length;q++){let z=Q[q];if($.type==="commit"&&z.type==="commit"&&z.commitIndex===$.index)return q;if($.type==="file"&&z.type==="file"&&z.fileIndex===$.index)return q}return 0}function o$($,J,K,Z){let X=Z$(J,K),Q=0;if($)Q=v$($,J,K);let q=Z==="down"?1:-1,z=Q+q;while(z>=0&&z<X.length){let V=l$(z,J,K);if(V)return V;z+=q}return $}function $9($){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 J9($){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 K9($){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 Z9($,J,K,Z){let X=J&&K,Q=$.node,q=$9($),z="";if(Q.isDirectory)z=Q.expanded?"▾ ":"▸ ";let V=J9(Q.gitStatus),Y=K9(Q.gitStatus),U=V?`${Y}${V}\x1B[0m `:"",j=Q.isDirectory&&Q.hasChangedChildren?`${"\x1B[33m"}●${"\x1B[0m"} `:"",B=q.length+z.length+(V?2:0)+(Q.hasChangedChildren&&Q.isDirectory?2:0),G=Math.max(5,Z-B-2),M=Q.isDirectory?`${Q.name}/`:Q.name;if(M.length>G)M=M.slice(0,G-1)+"…";let v=`\x1B[90m${q}\x1B[0m`;if(Q.isDirectory)if(v+=`\x1B[34m${z}\x1B[0m`,v+=j,X)v+=`\x1B[36m\x1B[1m\x1B[7m${M}\x1B[0m`;else v+=`\x1B[34m${M}\x1B[0m`;else if(v+=U,X)v+=`\x1B[36m\x1B[1m\x1B[7m${M}\x1B[0m`;else if(Q.gitStatus)v+=`${Y}${M}\x1B[0m`;else v+=M;return v}function e8($,J,K,Z,X=0,Q,q=!1,z=null){if(z)return`{red-fg}Error: ${X9(z)}{/red-fg}`;if(q)return"{gray-fg}Loading...{/gray-fg}";if($.length===0)return"{gray-fg}(empty directory){/gray-fg}";let V=Q?$.slice(X,X+Q):$.slice(X),Y=[];for(let U=0;U<V.length;U++){let j=X+U,B=Z9(V[U],j===J,K,Z);Y.push(`{escape}${B}{/escape}`)}return Y.join(`
|
|
7
|
+
`)}function X9($){return $.replace(/\{/g,"{{").replace(/\}/g,"}}")}function $0($){return $.length}var Q9={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"}},q9={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"}},z9={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"}},V9={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"}},Y9={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"}},U9={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"}},W$={dark:Q9,light:q9,"dark-colorblind":z9,"light-colorblind":V9,"dark-ansi":Y9,"light-ansi":U9},c=["dark","light","dark-colorblind","light-colorblind","dark-ansi","light-ansi"];function D$($){return W$[$]??W$.dark}function B9($){return!($.startsWith("index ")||$.startsWith("--- ")||$.startsWith("+++ ")||$.startsWith("similarity index"))}function J0($){if($.type!=="header")return!0;return B9($.content)}function A$($,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)G9($,J,Z);return Z}function G9($,J,K){let Z=K.map((X)=>X.text).join("");if(Z!==$)throw Error(`[LineBreaking] Content was lost during breaking!
|
|
8
8
|
Original (${$.length} chars): "${$.slice(0,50)}${$.length>50?"...":""}"
|
|
9
|
-
Joined (${
|
|
9
|
+
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!
|
|
10
10
|
Segment length: ${Q.text.length}, maxWidth: ${J}
|
|
11
|
-
Segment: "${Q.text.slice(0,50)}${Q.text.length>50?"...":""}"`)}if(
|
|
12
|
-
`);return
|
|
13
|
-
`)}catch{return $}}function x($){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
|
|
14
|
-
`))
|
|
15
|
-
`),totalRows:W,hunkCount:T,hunkBoundaries:A}}function
|
|
16
|
-
`),totalRows:
|
|
17
|
-
`),totalRows:A,hunkCount:
|
|
18
|
-
`)
|
|
19
|
-
`)
|
|
20
|
-
`)
|
|
21
|
-
`)}function
|
|
22
|
-
`)
|
|
11
|
+
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 r$($,J){if(J<=0)return 1;if($.length<=J)return 1;return Math.ceil($.length/J)}import n from"fast-diff";function K0($,J){if(!$||!J)return!1;let K=n($,J),Z=0,X=0;for(let[q,z]of K)if(X+=z.length,q===n.EQUAL)Z+=z.length;if(X===0)return!1;return Z/X>=0.5}function Z0($,J){let K=n($,J),Z=[],X=[];for(let[Q,q]of K)if(Q===n.EQUAL)Z.push({text:q,type:"same"}),X.push({text:q,type:"same"});else if(Q===n.DELETE)Z.push({text:q,type:"changed"});else if(Q===n.INSERT)X.push({text:q,type:"changed"});return{oldSegments:Z,newSegments:X}}import{createEmphasize as j9}from"emphasize";import{common as _9}from"lowlight";var s$=j9(_9),M9={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"},X0={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"},a$=null;function Q0(){if(!a$)a$=new Set(s$.listLanguages());return a$}function T$($){if(!$)return null;let J=$.split("/").pop()??"";if(X0[J]){let X=X0[J];return Q0().has(X)?X:null}let K=J.includes(".")?J.split(".").pop()?.toLowerCase():null;if(!K)return null;let Z=M9[K];if(!Z)return null;return Q0().has(Z)?Z:null}function q0($,J){if(!$||!J)return $;try{return s$.highlight(J,$).value}catch{return $}}function n$($,J){if(!J||$.length===0)return $;try{let K=$.join(`
|
|
12
|
+
`);return s$.highlight(J,K).value.replace(/\x1b\[0m/g,"\x1B[39m").split(`
|
|
13
|
+
`)}catch{return $}}function x($){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 z0($){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:x($)};case"deletion":return{type:"diff-del",lineNum:$.oldLineNum,content:x($)};case"context":return{type:"diff-context",lineNum:$.oldLineNum??$.newLineNum,content:x($)}}}function O9($){let J=$.match(/^diff --git a\/.+ b\/(.+)$/);return J?J[1]:null}function N$($){if(!$)return[];let J=$.lines.filter(J0),K=[],Z=[],X=null,Q=0;while(Q<J.length){let q=J[Q];if(q.type==="header"){let B=O9(q.content);if(B){if(X)Z.push(X),K.push({type:"spacer"});X={language:T$(B),startRowIndex:K.length,oldContent:[],oldRowIndices:[],newContent:[],newRowIndices:[]}}K.push(z0(q)),Q++;continue}if(q.type==="hunk"){K.push(z0(q)),Q++;continue}if(q.type==="context"){let B=x(q),G=K.length;if(K.push({type:"diff-context",lineNum:q.oldLineNum??q.newLineNum,content:B}),X&&X.language)X.oldContent.push(B),X.oldRowIndices.push(G),X.newContent.push(B),X.newRowIndices.push(G);Q++;continue}let z=[];while(Q<J.length&&J[Q].type==="deletion")z.push(J[Q]),Q++;let V=[];while(Q<J.length&&J[Q].type==="addition")V.push(J[Q]),Q++;let Y=new Map,U=new Map,j=Math.min(z.length,V.length);for(let B=0;B<j;B++){let G=x(z[B]),M=x(V[B]);if(K0(G,M)){let{oldSegments:v,newSegments:W}=Z0(G,M);Y.set(B,v),U.set(B,W)}}for(let B=0;B<z.length;B++){let G=z[B],M=x(G),v=Y.get(B),W=K.length;if(K.push({type:"diff-del",lineNum:G.oldLineNum,content:M,...v&&{wordDiffSegments:v}}),X&&X.language&&!v)X.oldContent.push(M),X.oldRowIndices.push(W)}for(let B=0;B<V.length;B++){let G=V[B],M=x(G),v=U.get(B),W=K.length;if(K.push({type:"diff-add",lineNum:G.newLineNum,content:M,...v&&{wordDiffSegments:v}}),X&&X.language&&!v)X.newContent.push(M),X.newRowIndices.push(W)}}if(X)Z.push(X);for(let q of Z){if(!q.language)continue;if(q.oldContent.length>0){let z=n$(q.oldContent,q.language);for(let V=0;V<q.oldRowIndices.length;V++){let Y=q.oldRowIndices[V],U=K[Y],j=z[V];if(j&&j!==U.content&&(U.type==="diff-del"||U.type==="diff-context"))U.highlighted=j}}if(q.newContent.length>0){let z=n$(q.newContent,q.language);for(let V=0;V<q.newRowIndices.length;V++){let Y=q.newRowIndices[V],U=K[Y],j=z[V];if(j&&j!==U.content&&(U.type==="diff-add"||U.type==="diff-context"))U.highlighted=j}}}return K}function Y0($,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: ${u8($.date)}`}),K.push({type:"spacer"});for(let Z of $.message.split(`
|
|
14
|
+
`))K.push({type:"commit-message",content:` ${Z}`});K.push({type:"spacer"})}return K.push(...N$(J)),K}function H$($){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 E$($,J,K){if(!K)return $;let X=Math.max(10,J),Q=[];for(let q of $)if(q.type==="diff-add"||q.type==="diff-del"||q.type==="diff-context"){let z=q.content;if(!z||z.length<=X){Q.push(q);continue}let V=A$(z,X);for(let Y=0;Y<V.length;Y++){let U=V[Y];Q.push({...q,content:U.text,lineNum:U.isContinuation?void 0:q.lineNum,isContinuation:U.isContinuation})}}else Q.push(q);return Q}function i$($){let J=[],K=-1;for(let Z=0;Z<$.length;Z++){let X=$[Z].type;if(X==="diff-hunk"){if(K!==-1)J.push({startRow:K,endRow:Z});K=Z}else if(X==="diff-header"||X==="spacer"){if(K!==-1)J.push({startRow:K,endRow:Z}),K=-1}}if(K!==-1)J.push({startRow:K,endRow:$.length});return J}function v9($,J){let K=$.match(/@@ -(\d+)(?:,\d+)? \+(\d+)/);if(!K)return 0;return J==="staged"?parseInt(K[2],10):parseInt(K[1],10)}function V0($,J){if(!$||$.lines.length===0)return{fileHeaders:[],hunks:[]};let K=[],Z=[],X=null,Q=0;for(let q of $.lines)if(q.type==="header"){if(X)Z.push(X),X=null;K.push(q)}else if(q.type==="hunk"){if(X)Z.push(X);X={headerLine:q,bodyLines:[],sortKey:v9(q.content,J),source:J,hunkIndex:Q++}}else if(X)X.bodyLines.push(q);if(X)Z.push(X);return{fileHeaders:K,hunks:Z}}function U0($,J){let K=V0($,"unstaged"),Z=V0(J,"staged"),X=[...K.hunks,...Z.hunks];X.sort((Y,U)=>Y.sortKey-U.sortKey);let q=[...K.fileHeaders.length>0?K.fileHeaders:Z.fileHeaders],z=[];for(let Y of X)q.push(Y.headerLine,...Y.bodyLines),z.push({source:Y.source,hunkIndex:Y.hunkIndex});return{rows:N$({raw:"",lines:q}),hunkMapping:z}}var B0=/\x1b\[[0-9;]*m/g;function k$($,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;B0.lastIndex=0;let Q;while((Q=B0.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 q="",z=0,V=J-K.length,Y=!1,U=!1;for(let j of Z)if(j.type==="ansi")q+=j.content,Y=!0;else{let B=V-z;if(B<=0){U=!0;break}if(j.content.length<=B)q+=j.content,z+=j.content.length;else{q+=j.content.slice(0,B),U=!0;break}}if(U){if(Y)q+="\x1B[0m";q+=K}return q}var C="\x1B[0m",_0="\x1B[1m",M0="\x1B[90m",X$="\x1B[36m",O0="\x1B[32m",W9="\x1B[33m",v0="\x1B[7m";function p($,J){if(J<=0||$.length<=J)return $;if(J<=1)return"…";return $.slice(0,J-1)+"…"}function W0($,J){if($===void 0)return" ".repeat(J);return String($).padStart(J," ")}function D9($){return $.replace(/\{/g,"{{").replace(/\}/g,"}}")}function G0($){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 A9($){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 T9($,J){if($.startsWith("diff --git")){let K=$.match(/diff --git a\/.+ b\/(.+)$/);if(K){let Z=J-6,X=p(K[1],Z);return`{escape}${_0}${X$}── ${X} ──${C}{/escape}`}}return`{escape}${M0}${p($,J)}${C}{/escape}`}function N9($,J){let K=$.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/);if(K){let Z=parseInt(K[1],10),X=K[2]?parseInt(K[2],10):1,Q=parseInt(K[3],10),q=K[4]?parseInt(K[4],10):1,z=K[5].trim(),V=Z+X-1,Y=Q+q-1,U=X===1?`${Z}`:`${Z}-${V}`,j=q===1?`${Q}`:`${Q}-${Y}`,B=`Lines ${U} → ${j}`,G=J-B.length-1,M=z&&G>3?" "+p(z,G):"";return`{escape}${X$}${B}${M0}${M}${C}{/escape}`}return`{escape}${X$}${p($,J)}${C}{/escape}`}function D0($,J,K){let Z=K?$:p($,J);return{display:Z,visibleLength:Z.length}}function t$($,J,K,Z,X,Q){let q=" ".repeat(Math.max(0,Z-$.length-K));return`{escape}${X}${Q}${$}${J}${q}${C}{/escape}`}function H9($,J,K,Z,X,Q){let{display:q}=D0(J,K,X),z=`${$}${q}`.padEnd(Z," "),V=Q==="add"?"green":"red";return`{${V}-bg}{white-fg}${D9(z)}{/white-fg}{/${V}-bg}`}function E9($,J,K){let Z="";for(let X of $)Z+=X.type==="changed"?`${J}${X.text}${K}`:X.text;return Z}function j0($,J,K,Z,X,Q,q){let z=q==="add"?"+":"-",V=$.isContinuation?"»":z,U=`${W0($.lineNum,J)} ${V} `,j=$.content||"";if(X.name.includes("ansi"))return H9(U,j,K,Z,Q,q);let{colors:B}=X,G=G0(q==="add"?B.addBg:B.delBg),M=A9("#ffffff"),{display:v,visibleLength:W}=D0(j,K,Q),A=!$.isContinuation&&(Q||j.length<=K);if($.wordDiffSegments&&A){let T=G0(q==="add"?B.addHighlight:B.delHighlight),N=E9($.wordDiffSegments,T,G);return t$(U,N,j.length,Z,G,M)}if($.highlighted&&A)return t$(U,$.highlighted,j.length,Z,G,M);return t$(U,v,W,Z,G,M)}function e$($,J,K,Z,X,Q){switch($.type){case"diff-header":return T9($.content,Z);case"diff-hunk":return N9($.content,Z);case"diff-add":return j0($,J,K,Z,X,Q,"add");case"diff-del":return j0($,J,K,Z,X,Q,"del");case"diff-context":{let q=$.isContinuation,z=q?"»":" ",Y=`${W0($.lineNum,J)} ${z} `,U=$.content||"",j=`\x1B[90m${Y}\x1B[0m`;if($.highlighted&&!q){let G=Q?$.highlighted:k$($.highlighted,K);return`{escape}${j}${G}${C}{/escape}`}let B=Q?U:p(U,K);return`{escape}${j}${B}${C}{/escape}`}case"commit-header":return`{escape}${W9}${p($.content,Z)}${C}{/escape}`;case"commit-message":return`{escape}${p($.content,Z)}${C}{/escape}`;case"spacer":return""}}function $8($,J,K=0,Z,X="dark",Q=!1,q,z){let V=q!==void 0&&q>=0,Y=N$($);if(Y.length===0)return{content:"{gray-fg}No diff to display{/gray-fg}",totalRows:0,hunkCount:0,hunkBoundaries:[]};let U=D$(X),j=H$(Y),B=V?1:0,G=J-j-5-B,M=J-2,v=E$(Y,G,Q),W=v.length,A=i$(v),T=A.length,N=Math.min(q??0,T-1),_=V&&T>0?A[N]:null,O=K;return{content:(Z?v.slice(O,O+Z):v.slice(O)).map((H,R)=>{let h=O+R,P=e$(H,j,G,M,U,Q);if(!V)return P;let d=_&&h>=_.startRow&&h<_.endRow,$$=d?`{escape}${z?O0:X$}▌${C}{/escape}`:" ";if(d&&H.type==="diff-hunk")return $$+P.replace("{escape}",`{escape}${v0}`);return $$+P}).join(`
|
|
15
|
+
`),totalRows:W,hunkCount:T,hunkBoundaries:A}}function A0($,J,K,Z=0,X,Q="dark",q=!1){let z=Y0($,J);if(z.length===0)return{content:"{gray-fg}No commit selected{/gray-fg}",totalRows:0,hunkCount:0,hunkBoundaries:[]};let V=D$(Q),Y=H$(z),U=K-Y-5,j=K-2,B=E$(z,U,q),G=B.length;return{content:(X?B.slice(Z,Z+X):B.slice(Z)).map((W)=>e$(W,Y,U,j,V,q)).join(`
|
|
16
|
+
`),totalRows:G,hunkCount:0,hunkBoundaries:[]}}function T0($,J,K,Z=0,X,Q="dark",q=!1,z){let{rows:V,hunkMapping:Y}=U0($,J);if(V.length===0)return{content:"{gray-fg}No diff to display{/gray-fg}",totalRows:0,hunkCount:0,hunkBoundaries:[],hunkMapping:[]};let U=z!==void 0&&z>=0,j=D$(Q),B=H$(V),G=U?1:0,M=K-B-5-G,v=K-2,W=E$(V,M,q),A=W.length,T=i$(W),N=T.length,_=Math.min(z??0,N-1),O=new Map;if(U)for(let R=0;R<T.length;R++){let h=T[R];for(let P=h.startRow;P<h.endRow;P++)O.set(P,R)}let D=Z;return{content:(X?W.slice(D,D+X):W.slice(D)).map((R,h)=>{let P=D+h,d=e$(R,B,M,v,j,q);if(!U)return d;let q$=O.get(P);if(q$===void 0)return" "+d;let $$=q$===_,g5=Y[q$]?.source==="staged"?O0:X$,I8=`{escape}${$$?_0:""}${g5}▌${C}{/escape}`;if($$&&R.type==="diff-hunk")return I8+d.replace("{escape}",`{escape}${v0}`);return I8+d}).join(`
|
|
17
|
+
`),totalRows:A,hunkCount:N,hunkBoundaries:T,hunkMapping:Y}}function N0($){let{state:J,stagedCount:K,width:Z,branch:X,remoteState:Q,stashList:q,headCommit:z}=$,V=[],Y="{bold}Commit Message{/bold}";if(J.amend)Y+=" {yellow-fg}(amending){/yellow-fg}";V.push(Y),V.push("");let U=J.inputFocused?"cyan":"gray",j=Math.max(20,Z-6);V.push(`{${U}-fg}┌${"─".repeat(j+2)}┐{/${U}-fg}`);let B=J.message||(J.inputFocused?"":"Press i or Enter to edit..."),G=J.message?"":"{gray-fg}",M=J.message?"":"{/gray-fg}",v=B.length>j?B.slice(0,j-1)+"…":B.padEnd(j);V.push(`{${U}-fg}│{/${U}-fg} ${G}${v}${M} {${U}-fg}│{/${U}-fg}`),V.push(`{${U}-fg}└${"─".repeat(j+2)}┘{/${U}-fg}`),V.push("");let W=J.amend?"[x]":"[ ]",A=J.amend?"green":"gray";if(V.push(`{${A}-fg}${W}{/${A}-fg} Amend {gray-fg}(a){/gray-fg}`),J.error)V.push(""),V.push(`{red-fg}${J.error}{/red-fg}`);if(J.isCommitting)V.push(""),V.push("{yellow-fg}Committing...{/yellow-fg}");V.push("");let T=J.inputFocused?"Enter: commit | Ctrl+a: amend | Esc: unfocus":"i/Enter: edit | a: amend | Esc: back";V.push(`{gray-fg}Staged: ${K} file(s) | ${T}{/gray-fg}`);let N=q??[];if(V.push(""),V.push(`{gray-fg}${"─".repeat(3)} Stash (${N.length}) ${"─".repeat(3)}{/gray-fg}`),N.length>0){for(let O=0;O<Math.min(N.length,5);O++){let D=N[O],k=D.message.length>Z-10?D.message.slice(0,Z-13)+"…":D.message;V.push(`{gray-fg}{${O}}{/gray-fg}: ${k}`)}if(N.length>5)V.push(`{gray-fg}... ${N.length-5} more{/gray-fg}`)}else V.push("{gray-fg}(empty){/gray-fg}");if(V.push("{gray-fg}S: save | o: pop | l: list{/gray-fg}"),X){V.push(""),V.push(`{gray-fg}${"─".repeat(3)} Branch ${"─".repeat(3)}{/gray-fg}`);let _=`{bold}* ${X.current}{/bold}`;if(X.tracking)_+=` {gray-fg}→{/gray-fg} ${X.tracking}`;V.push(_),V.push("{gray-fg}b: switch/create{/gray-fg}")}if(V.push(""),V.push(`{gray-fg}${"─".repeat(3)} Undo ${"─".repeat(3)}{/gray-fg}`),z)V.push(`{gray-fg}HEAD: {yellow-fg}${z.shortHash}{/yellow-fg} ${z.message}{/gray-fg}`);if(V.push("{gray-fg}X: soft reset HEAD~1{/gray-fg}"),X){if(V.push(""),V.push(`{gray-fg}${"─".repeat(3)} Remote ${"─".repeat(3)}{/gray-fg}`),X.tracking){let _=`${X.current} {gray-fg}→{/gray-fg} ${X.tracking}`;if(X.ahead>0)_+=` {green-fg}↑${X.ahead}{/green-fg}`;if(X.behind>0)_+=` {red-fg}↓${X.behind}{/red-fg}`;V.push(_)}else V.push(`{gray-fg}${X.current} (no remote tracking){/gray-fg}`);if(Q?.inProgress&&Q.operation){let _={push:"Pushing...",fetch:"Fetching...",pull:"Rebasing...",stash:"Stashing...",stashPop:"Popping stash...",branchSwitch:"Switching branch...",branchCreate:"Creating branch...",softReset:"Resetting...",cherryPick:"Cherry-picking...",revert:"Reverting..."};V.push(`{yellow-fg}${_[Q.operation]??""}{/yellow-fg}`)}else if(Q?.error){let _=Q.error.length>50?Q.error.slice(0,50)+"…":Q.error;V.push(`{red-fg}${_}{/red-fg}`)}else if(Q?.lastResult)V.push(`{green-fg}${Q.lastResult}{/green-fg}`);V.push("{gray-fg}P: push | F: fetch | R: pull --rebase{/gray-fg}")}return V}function H0($){return N0($).length}function E0($,J,K,Z,X,Q,q,z=0,V){let Y=N0({state:$,stagedCount:J,width:K,branch:Z,remoteState:X,stashList:Q,headCommit:q});if(V&&Y.length>V)return Y.slice(z,z+V).join(`
|
|
18
|
+
`);return Y.join(`
|
|
19
|
+
`)}function J8($,J,K){if(!$)return[];let Z=$.split(`
|
|
20
|
+
`),X=[],Q=J?T$(J):null;for(let q=0;q<Z.length;q++){let z=Z[q],V=Q?q0(z,Q):void 0;X.push({type:"code",lineNum:q+1,content:z,highlighted:V})}if(K)X.push({type:"truncation",content:"(file truncated)"});return X}function k0($,J,K){if(!K)return $;let X=Math.max(10,J),Q=[];for(let q of $)if(q.type==="code"){let z=q.content;if(!z||z.length<=X){Q.push(q);continue}let V=A$(z,X);for(let Y=0;Y<V.length;Y++){let U=V[Y];Q.push({type:"code",lineNum:U.isContinuation?0:q.lineNum,content:U.text,highlighted:void 0,isContinuation:U.isContinuation})}}else Q.push(q);return Q}function R0($,J,K){if(!K)return $.length;let X=Math.max(10,J),Q=0;for(let q of $)if(q.type==="code"){let z=q.content;if(!z||z.length<=X)Q+=1;else Q+=r$(z,X)}else Q+=1;return Q}function K8($){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 L0="\x1B[0m",k9="\x1B[90m",R9="\x1B[36m",L9="\x1B[33m";function F0($,J,K,Z=0,X,Q=!1,q=!1){if(!$)return"{gray-fg}Select a file to view its contents{/gray-fg}";if(!J)return"{gray-fg}Loading...{/gray-fg}";let z=J8(J,$,Q);if(z.length===0)return"{gray-fg}(empty file){/gray-fg}";let V=K8(z),Y=K-V-2,U=k0(z,Y,q),j=X?U.slice(Z,Z+X):U.slice(Z),B=[];for(let G of j){if(G.type==="truncation"){B.push(`{escape}${L9}${G.content}${L0}{/escape}`);continue}let M=G.isContinuation??!1,v;if(M)v=">>".padStart(V," ");else v=String(G.lineNum).padStart(V," ");let W=G.content,A=!q&&W.length>Y,T=G.highlighted&&!M,N;if(T&&G.highlighted)N=A?k$(G.highlighted,Y):G.highlighted;else{let D=W;if(A)D=D.slice(0,Math.max(0,Y-1))+"...";N=D}let O=`{escape}${M?R9:k9}${v}${L0} ${N||" "}{/escape}`;B.push(O)}return B.join(`
|
|
21
|
+
`)}function I0($,J,K,Z,X){if(!$)return 0;let Q=J8($,J,K),q=K8(Q),z=Z-q-2;return R0(Q,z,X)}function y0($,J,K,Z,X,Q,q,z,V,Y){if($.bottomTab==="history")return m8(K,$.historySelectedIndex,$.currentPane==="history",q,$.historyScrollOffset,z);if($.bottomTab==="compare"){let U=Z?.commits??[],j=Z?.files??[];return i8(U,j,X,$.currentPane==="compare",q,$.compareScrollOffset,z)}if($.bottomTab==="explorer"){let U=Q?.displayRows??[];return e8(U,$.explorerSelectedIndex,$.currentPane==="explorer",q,$.explorerScrollOffset,z,Q?.isLoading??!1,Q?.error??null)}if($.flatViewMode&&Y)return p8(Y,$.selectedIndex,$.currentPane==="files",q,$.fileListScrollOffset,z);return C8(J,$.selectedIndex,$.currentPane==="files",q,$.fileListScrollOffset,z,V)}function C0($,J,K,Z,X,Q,q,z,V,Y,U,j,B,G,M,v,W){if($.bottomTab==="commit"){let D=H0({state:Q,stagedCount:q,width:V,branch:G,remoteState:M,stashList:v,headCommit:W});return{content:E0(Q,q,V,G,M,v,W,$.diffScrollOffset,Y),totalRows:D,hunkCount:0,hunkBoundaries:[]}}if($.bottomTab==="history"){let O=K?.selectedCommit??null,D=K?.commitDiff??null,{content:k,totalRows:H}=A0(O,D,V,$.diffScrollOffset,Y,z,$.wrapMode);return{content:k,totalRows:H,hunkCount:0,hunkBoundaries:[]}}if($.bottomTab==="compare"){let O=Z?.diff??null;if(O){let{content:D,totalRows:k}=$8(O,V,$.diffScrollOffset,Y,z,$.wrapMode);return{content:D,totalRows:k,hunkCount:0,hunkBoundaries:[]}}return{content:"{gray-fg}Select a commit or file to view diff{/gray-fg}",totalRows:0,hunkCount:0,hunkBoundaries:[]}}if($.bottomTab==="explorer")return{content:F0(X?.path??null,X?.content??null,V,$.explorerFileScrollOffset,Y,X?.truncated??!1,$.wrapMode),totalRows:0,hunkCount:0,hunkBoundaries:[]};if($.flatViewMode&&B){let O=T0(B.unstaged,B.staged,V,$.diffScrollOffset,Y,z,$.wrapMode,U);return{content:O.content,totalRows:O.totalRows,hunkCount:O.hunkCount,hunkBoundaries:O.hunkBoundaries,hunkMapping:O.hunkMapping}}let{content:A,totalRows:T,hunkCount:N,hunkBoundaries:_}=$8(J,V,$.diffScrollOffset,Y,z,$.wrapMode,U,j);return{content:A,totalRows:T,hunkCount:N,hunkBoundaries:_}}var R$=3;function b0($,J,K){$.topPane.on("wheeldown",()=>{P0(R$,$,K)}),$.topPane.on("wheelup",()=>{P0(-R$,$,K)}),$.bottomPane.on("wheeldown",()=>{S0(R$,$,K)}),$.bottomPane.on("wheelup",()=>{S0(-R$,$,K)}),$.topPane.on("click",(Z)=>{let X=$.screenYToTopPaneRow(Z.y);if(X>=0)I9(X,Z.x,J,K)}),$.bottomPane.on("click",(Z)=>{let X=$.screenYToBottomPaneRow(Z.y);if(X>=0)if(K.uiState.state.bottomTab==="commit")if(X===6)J.toggleAmend();else J.focusCommitInput();else J.selectHunkAtRow(X)}),$.footerBox.on("click",(Z)=>{y9(Z.x,J,K)})}function F9($,J,K,Z){let X=Z.uiState.state;if(X.flatViewMode){let q=$+X.fileListScrollOffset-1,z=Z.getCachedFlatFiles();if(q<0||q>=z.length)return;if(J!==void 0&&J>=2&&J<=4)K.toggleFileByIndex(q);else Z.uiState.setSelectedIndex(q),K.selectFileByIndex(q)}else{let Q=Z.getStatusFiles(),q=S8($+X.fileListScrollOffset,Q);if(q===null||q<0)return;if(J!==void 0&&J>=2&&J<=4)K.toggleFileByIndex(q);else Z.uiState.setSelectedIndex(q),K.selectFileByIndex(q)}}function I9($,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(),q=Z.getCompareFiles(),z=l$(X.compareScrollOffset+$,Q,q);if(z)K.selectCompareItem(z)}else if(X.bottomTab==="explorer"){let Q=X.explorerScrollOffset+$,q=Z.getExplorerManager(),z=q?.state.selectedIndex===Q,V=q?.state.displayRows[Q];if(z&&V?.node.isDirectory)K.enterExplorerDirectory();else q?.selectIndex(Q),Z.uiState.setExplorerSelectedIndex(Q)}else F9($,J,K,Z)}function y9($,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:q,width:z}of X){let V=Q-z-1;if($>=V&&$<Q){K.uiState.setTab(q);return}Q=V}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.getExplorerManager()?.toggleShowOnlyChanges();else if($===0)K.uiState.openModal("hotkeys")}function P0($,J,K){let Z=K.uiState.state,X=J.dimensions.topPaneHeight;if(Z.bottomTab==="history"){let Q=K.getHistoryCommitCount(),q=Math.max(0,Q-X),z=Math.min(q,Math.max(0,Z.historyScrollOffset+$));K.uiState.setHistoryScrollOffset(z)}else if(Z.bottomTab==="compare"){let Q=t8(K.getCompareCommits(),K.getCompareFiles()),q=Math.max(0,Q-X),z=Math.min(q,Math.max(0,Z.compareScrollOffset+$));K.uiState.setCompareScrollOffset(z)}else if(Z.bottomTab==="explorer"){let Q=$0(K.getExplorerManager()?.state.displayRows??[]),q=Math.max(0,Q-X),z=Math.min(q,Math.max(0,Z.explorerScrollOffset+$));K.uiState.setExplorerScrollOffset(z)}else{let Q=Z.flatViewMode?g8(K.getCachedFlatFiles()):P8(K.getStatusFiles()),q=Math.max(0,Q-X),z=Math.min(q,Math.max(0,Z.fileListScrollOffset+$));K.uiState.setFileListScrollOffset(z)}}function S0($,J,K){let Z=K.uiState.state,X=J.dimensions.bottomPaneHeight,Q=K.getScreenWidth();if(Z.bottomTab==="explorer"){let q=K.getExplorerManager()?.state.selectedFile,z=I0(q?.content??null,q?.path??null,q?.truncated??!1,Q,Z.wrapMode),V=Math.max(0,z-X),Y=Math.min(V,Math.max(0,Z.explorerFileScrollOffset+$));K.uiState.setExplorerFileScrollOffset(Y)}else{let q=Math.max(0,K.getBottomPaneTotalRows()-X),z=Math.min(q,Math.max(0,Z.diffScrollOffset+$));K.uiState.setDiffScrollOffset(z)}}import*as l from"node:fs";import*as F$ from"node:path";import{watch as b9}from"chokidar";import{EventEmitter as w9}from"node:events";import*as F from"node:fs";import*as t from"node:path";import*as L$ from"node:os";var C9={targetFile:t.join(L$.homedir(),".cache","diffstalker","target"),watcherEnabled:!1,debug:!1,theme:"dark"},i=t.join(L$.homedir(),".config","diffstalker","config.json"),P9=["dark","light","dark-colorblind","light-colorblind","dark-ansi","light-ansi"];function S9($){return typeof $==="string"&&P9.includes($)}function w0(){let $={...C9};if(process.env.DIFFSTALKER_PAGER)$.pager=process.env.DIFFSTALKER_PAGER;if(F.existsSync(i))try{let J=JSON.parse(F.readFileSync(i,"utf-8"));if(J.pager)$.pager=J.pager;if(J.targetFile)$.targetFile=J.targetFile;if(S9(J.theme))$.theme=J.theme;if(typeof J.splitRatio==="number"&&J.splitRatio>=0.15&&J.splitRatio<=0.85)$.splitRatio=J.splitRatio}catch{}return $}function Z8($){let J=t.dirname(i);if(!F.existsSync(J))F.mkdirSync(J,{recursive:!0});let K={};if(F.existsSync(i))try{K=JSON.parse(F.readFileSync(i,"utf-8"))}catch{}Object.assign(K,$),F.writeFileSync(i,JSON.stringify(K,null,2)+`
|
|
22
|
+
`)}function x0($){let J=t.dirname($);if(!F.existsSync(J))F.mkdirSync(J,{recursive:!0})}function p0($){let J=L$.homedir();if($.startsWith(J))return"~"+$.slice(J.length);return $}import*as g0 from"node:path";import*as X8 from"node:os";function u0($){if($.startsWith("~/"))return g0.join(X8.homedir(),$.slice(2));if($==="~")return X8.homedir();return $}function Q8($){let J=$.split(`
|
|
23
|
+
`);for(let K=J.length-1;K>=0;K--){let Z=J[K].trim();if(Z)return Z}return""}class q8 extends w9{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=u0($);return F$.isAbsolute(J)?J:F$.resolve(J)}readTargetDebounced(){if(this.debounceTimer)clearTimeout(this.debounceTimer);this.debounceTimer=setTimeout(()=>{this.readTarget()},100)}readTarget(){try{let $=l.readFileSync(this.targetFile,"utf-8"),J=Q8($);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
|
|
23
24
|
`),process.stderr.write(` Source file: ${this.targetFile}
|
|
24
25
|
`),process.stderr.write(` Raw content: "${J}"
|
|
25
26
|
`),process.stderr.write(` Previous: "${this.lastReadPath??"(none)"}"
|
|
26
|
-
`),process.stderr.write(` Resolved: "${
|
|
27
|
-
`);this.lastReadPath=
|
|
27
|
+
`),process.stderr.write(` Resolved: "${K}"
|
|
28
|
+
`);this.lastReadPath=K,this.updateState({path:K,lastUpdate:Z,rawContent:J})}}catch{}}start(){if(x0(this.targetFile),!l.existsSync(this.targetFile))l.writeFileSync(this.targetFile,"");try{let $=l.readFileSync(this.targetFile,"utf-8"),J=Q8($);if(J){let K=this.processContent(J),Z=new Date;if(this.debug&&K)process.stderr.write(`[diffstalker ${Z.toISOString()}] Initial path read
|
|
28
29
|
`),process.stderr.write(` Source file: ${this.targetFile}
|
|
29
30
|
`),process.stderr.write(` Raw content: "${J}"
|
|
30
|
-
`),process.stderr.write(` Resolved: "${
|
|
31
|
-
`);this.lastReadPath=
|
|
32
|
-
`).filter((Y)=>Y.length>0);for(let Y of V)
|
|
33
|
-
|
|
31
|
+
`),process.stderr.write(` Resolved: "${K}"
|
|
32
|
+
`);this.lastReadPath=K,this._state={path:K,lastUpdate:Z,rawContent:J,sourceFile:this.targetFile}}}catch{}this.watcher=b9(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 I${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 q8(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 x9($){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 p9($){let J=$.current.length;if($.tracking)J+=3+$.tracking.length;if($.ahead>0)J+=3+String($.ahead).length;if($.behind>0)J+=3+String($.behind).length;return J}function m0($,J,K,Z,X,Q){if(!$)return"{gray-fg}Waiting for target path...{/gray-fg}";let q=p0($),z=Z==="Not a git repository",V=`{bold}{cyan-fg}${q}{/cyan-fg}{/bold}`;if(K)V+=" {yellow-fg}⟳{/yellow-fg}";if(z)V+=" {yellow-fg}(not a git repository){/yellow-fg}";else if(Z)V+=` {red-fg}(${Z}){/red-fg}`;let Y="",U=0;if(Q){if(Q.inProgress&&Q.operation){let G={push:"pushing...",fetch:"fetching...",pull:"rebasing...",stash:"stashing...",stashPop:"popping stash...",branchSwitch:"switching branch...",branchCreate:"creating branch...",softReset:"resetting...",cherryPick:"cherry-picking...",revert:"reverting..."}[Q.operation]??"";Y=` {yellow-fg}${G}{/yellow-fg}`,U=1+G.length}else if(Q.error){let B=Q.error.length>40?Q.error.slice(0,40)+"…":Q.error;Y=` {red-fg}${B}{/red-fg}`,U=1+B.length}else if(Q.lastResult)Y=` {green-fg}${Q.lastResult}{/green-fg}`,U=1+Q.lastResult.length}let j=J?x9(J):"";if(j){let B=q.length;if(K)B+=2;if(z)B+=24;else if(Z)B+=Z.length+3;B+=U;let G=J?p9(J):0,M=Math.max(1,X-B-G-2);return V+Y+" ".repeat(M)+j}return V+Y}function f0($){return $.replace(/\{[^}]+\}/g,"").length}function y$($,J){return J?`{blue-fg}[${$}]{/blue-fg}`:`{gray-fg}[${$}]{/gray-fg}`}function g9($,J,K,Z,X,Q){let q=[];if(q.push($?"{yellow-fg}[scroll]{/yellow-fg}":"{yellow-fg}m:[select]{/yellow-fg}"),q.push(y$("auto",J)),q.push(y$("wrap",K)),q.push(y$("follow",Z)),Q==="explorer")q.push(y$("changes",X));return q.join(" ")}function h0($,J,K,Z,X,Q,q,z){let V="{gray-fg}?{/gray-fg} ";if(V+=g9(J,K,Z,X,Q,$),$==="diff"&&z==="diff")V+=" {gray-fg}n/N:hunk s:toggle{/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:M,label:v,tab:W})=>{if($===W)return`{bold}{cyan-fg}[${M}]${v}{/cyan-fg}{/bold}`;return`[${M}]${v}`}).join(" "),j=f0(V),B=f0(U),G=Math.max(1,q-j-B);return V+" ".repeat(G)+U}import*as e from"node:fs";import*as y from"node:path";import{EventEmitter as f9}from"node:events";import{simpleGit as u9}from"simple-git";async function C$($,J){if(J.length===0)return new Set;let K=u9($),Z=new Set,X=100;for(let Q=0;Q<J.length;Q+=X){let q=J.slice(Q,Q+X);try{let V=(await K.raw(["check-ignore",...q])).trim().split(`
|
|
33
|
+
`).filter((Y)=>Y.length>0);for(let Y of V)Z.add(Y)}catch{}}return Z}import{simpleGit as E}from"simple-git";import{execFileSync as l0}from"node:child_process";import*as o0 from"node:fs";import*as r0 from"node:path";function d0($){let J=new Map;for(let K of $.trim().split(`
|
|
34
|
+
`)){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),q=Z.slice(2).join("\t");J.set(q,{insertions:X,deletions:Q})}}return J}async function m9($,J){try{let K=r0.join($,J);return(await o0.promises.readFile(K,"utf-8")).split(`
|
|
35
|
+
`).filter((X)=>X.length>0).length}catch{return 0}}function c0($){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 z8($){let J=E($);try{if(!await J.checkIsRepo())return{files:[],branch:{current:"",ahead:0,behind:0},isRepo:!1};let Z=await J.status(),X=[],Q=new Set,q=Z.files.filter((G)=>G.working_dir==="?").map((G)=>G.path),z=await C$($,q);for(let G of Z.files){if(G.index==="!"||G.working_dir==="!"||z.has(G.path))continue;let M=`${G.path}-${G.index!==" "&&G.index!=="?"}`;if(Q.has(M))continue;if(Q.add(M),G.index&&G.index!==" "&&G.index!=="?")X.push({path:G.path,status:c0(G.index),staged:!0});if(G.working_dir&&G.working_dir!==" ")X.push({path:G.path,status:G.working_dir==="?"?"untracked":c0(G.working_dir),staged:!1})}let[V,Y]=await Promise.all([J.diff(["--cached","--numstat"]).catch(()=>""),J.diff(["--numstat"]).catch(()=>"")]),U=d0(V),j=d0(Y);for(let G of X){let M=G.staged?U.get(G.path):j.get(G.path);if(M)G.insertions=M.insertions,G.deletions=M.deletions}let B=X.filter((G)=>G.status==="untracked");if(B.length>0){let G=await Promise.all(B.map((M)=>m9($,M.path)));for(let M=0;M<B.length;M++)B[M].insertions=G[M],B[M].deletions=0}return{files:X,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 a0($,J){await E($).add(J)}async function s0($,J){await E($).reset(["HEAD","--",J])}async function n0($){await E($).add("-A")}async function i0($){await E($).reset(["HEAD"])}async function t0($,J){await E($).checkout(["--",J])}async function e0($,J,K=!1){await E($).commit(J,void 0,K?{"--amend":null}:void 0)}async function $5($){let J=E($);try{return(await J.log({n:1})).latest?.message||""}catch{return""}}function J5($,J){l0("git",["apply","--cached","--unidiff-zero"],{cwd:$,input:J,encoding:"utf-8"})}function K5($,J){l0("git",["apply","--cached","--reverse","--unidiff-zero"],{cwd:$,input:J,encoding:"utf-8"})}async function Z5($){let Z=(await E($).push()).pushed;if(Z.length===0)return"Everything up-to-date";return Z.map((X)=>`${X.local} → ${X.remote}`).join(", ")}async function X5($){return await E($).fetch(),"Fetch complete"}async function Q5($){let K=await E($).pull(["--rebase"]);if(K.summary.changes===0&&K.summary.insertions===0&&K.summary.deletions===0)return"Already up-to-date";return`${K.summary.changes} file(s) changed`}async function q5($,J=50){let K=E($);try{return(await K.log({n:J})).all.map((X)=>({hash:X.hash,shortHash:X.hash.slice(0,7),message:X.message.split(`
|
|
36
|
+
`)[0],author:X.author_name,date:new Date(X.date),refs:X.refs||""}))}catch{return[]}}async function z5($){let J=E($);try{return(await J.stashList()).all.map((Z,X)=>({index:X,message:Z.message}))}catch{return[]}}async function V5($,J){let K=E($),Z=["push"];if(J)Z.push("-m",J);return await K.stash(Z),"Stashed"}async function Y5($,J=0){return await E($).stash(["pop",`stash@{${J}}`]),"Stash popped"}async function U5($){let K=await E($).branchLocal();return K.all.map((Z)=>({name:Z,current:Z===K.current,tracking:K.branches[Z]?.label||void 0}))}async function B5($,J){return await E($).checkout(J),`Switched to ${J}`}async function G5($,J){return await E($).checkoutLocalBranch(J),`Created ${J}`}async function j5($,J=1){return await E($).reset(["--soft",`HEAD~${J}`]),"Reset done"}async function _5($,J){return await E($).raw(["cherry-pick",J]),"Cherry-picked"}async function M5($,J){return await E($).revert(J),"Reverted"}async function O5($){return(await E($).raw(["ls-files","-z","--cached","--others","--exclude-standard"])).split("\x00").filter((Z)=>Z.length>0)}var h9=1048576,d9=102400;function c9($){let J=Math.min($.length,8192);for(let K=0;K<J;K++)if($[K]===0)return!0;return!1}class V8 extends f9{repoPath;options;expandedPaths=new Set;gitStatusMap={files:new Map,directories:new Set};_cachedFilePaths=null;_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.loadFilePaths(),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=y.join(this.repoPath,$);if(!(await e.promises.stat(K)).isDirectory())return{name:y.basename($)||this.getRepoName(),path:$,isDirectory:!1,expanded:!1,children:[],childrenLoaded:!0};let X=this.expandedPaths.has($),Q={name:y.basename($)||this.getRepoName(),path:$,isDirectory:!0,expanded:X,children:[],childrenLoaded:!1};if($===""||X)await this.loadChildrenForNode(Q);return Q}catch{return null}}async loadChildrenForNode($){if($.childrenLoaded)return;try{let J=y.join(this.repoPath,$.path),K=await e.promises.readdir(J,{withFileTypes:!0}),Z=K.map((q)=>$.path?y.join($.path,q.name):q.name),X=this.options.hideGitignored?await C$(this.repoPath,Z):new Set,Q=[];for(let q of K){if(this.options.hideHidden&&q.name.startsWith("."))continue;let z=$.path?y.join($.path,q.name):q.name;if(this.options.hideGitignored&&X.has(z))continue;let V=q.isDirectory(),Y=this.expandedPaths.has(z),U={name:q.name,path:z,isDirectory:V,expanded:Y,children:[],childrenLoaded:!V};if(V&&Y)await this.loadChildrenForNode(U);Q.push(U)}Q.sort((q,z)=>{if(q.isDirectory&&!z.isDirectory)return-1;if(!q.isDirectory&&z.isDirectory)return 1;return q.name.localeCompare(z.name)}),this.collapseNode($,Q),$.childrenLoaded=!0}catch{$.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)}}shouldIncludeNode($){if(!this.options.showOnlyChanges)return!0;if($.isDirectory)return!!$.hasChangedChildren;return!!$.gitStatus}flattenTree($){let J=[],K=(Z,X,Q)=>{for(let q=0;q<Z.children.length;q++){let z=Z.children[q],V=q===Z.children.length-1;if(!this.shouldIncludeNode(z))continue;if(J.push({node:z,depth:X,isLast:V,parentIsLast:[...Q]}),z.isDirectory&&z.expanded)K(z,X+1,[...Q,V])}};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 y.basename(this.repoPath)||"repo"}async loadDirectory($){this._state.currentPath=$,await this.loadTree()}async loadFile($){try{let J=y.join(this.repoPath,$),K=await e.promises.stat(J);if(K.size>h9){this.updateState({selectedFile:{path:$,content:`File too large to display (${(K.size/1024/1024).toFixed(2)} MB).
|
|
37
|
+
Maximum size: 1 MB`,truncated:!0}});return}let Z=await e.promises.readFile(J);if(c9(Z)){this.updateState({selectedFile:{path:$,content:"Binary file - cannot display"}});return}let X=Z.toString("utf-8"),Q=!1;if(K.size>d9)X=`Warning: Large file (${(K.size/1024).toFixed(1)} KB)
|
|
34
38
|
|
|
35
39
|
`+X;let q=5000,z=X.split(`
|
|
36
40
|
`);if(z.length>q)X=z.slice(0,q).join(`
|
|
37
41
|
`)+`
|
|
38
42
|
|
|
39
|
-
... (truncated, ${z.length-q} 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
|
|
40
|
-
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import
|
|
41
|
-
`)),this.screen.render()}renderGroups($,J){let
|
|
42
|
-
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import
|
|
43
|
-
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import
|
|
44
|
-
`)),this.screen.render()}close(){this.textbox.destroy(),this.box.destroy()}focus(){this.textbox.focus()}}import
|
|
45
|
-
`)){
|
|
46
|
-
`).
|
|
47
|
-
`)
|
|
48
|
-
`);if(
|
|
49
|
-
`)
|
|
43
|
+
... (truncated, ${z.length-q} 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=y.dirname(Z);if(X==="."||X==="")return;let Q=Z.split("/");for(let q=Q.length-1;q>0;q--){let z=Q.slice(0,q).join("/");if(this.expandedPaths.has(z)){this.expandedPaths.delete(z);let V=this.findNodeByPath(z);if(V)V.expanded=!1;this.refreshDisplayRows();let U=this._state.displayRows.findIndex((j)=>j.node.path===z);if(U>=0)this.updateState({selectedIndex:U,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 loadFilePaths(){try{this._cachedFilePaths=await O5(this.repoPath)}catch{this._cachedFilePaths=[]}}getCachedFilePaths(){return this._cachedFilePaths??[]}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 l9 from"neo-blessed";class Y8{box;screen;selectedIndex;currentTheme;onSelect;onCancel;constructor($,J,K,Z){if(this.screen=$,this.currentTheme=J,this.onSelect=K,this.onCancel=Z,this.selectedIndex=c.indexOf(J),this.selectedIndex<0)this.selectedIndex=0;let X=50,Q=c.length+12;this.box=l9.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 $=c[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(c.length-1,this.selectedIndex+1),this.render()})}render(){let $=[];$.push("{bold}{cyan-fg} Select Theme{/cyan-fg}{/bold}"),$.push("");for(let J=0;J<c.length;J++){let K=c[J],Z=W$[K],X=J===this.selectedIndex,Q=K===this.currentTheme,q=X?"{cyan-fg}{bold}> ":" ";if(q+=Z.displayName,X)q+="{/bold}{/cyan-fg}";if(Q)q+=" {gray-fg}(current){/gray-fg}";$.push(q)}$.push(""),$.push("{gray-fg}Preview:{/gray-fg}"),$.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(`
|
|
44
|
+
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import o9 from"neo-blessed";var g=[{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"},{key:"P",description:"Push to remote"},{key:"F",description:"Fetch from remote"},{key:"R",description:"Pull --rebase"},{key:"S",description:"Stash save (global)"}]},{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:"h",description:"Flat file view"},{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"},{key:"/",description:"Find file"},{key:"Ctrl+P",description:"Find file (any tab)"},{key:"g",description:"Show changes only"}]},{title:"Commit Panel",entries:[{key:"i/Enter",description:"Edit message"},{key:"a",description:"Toggle amend"},{key:"Ctrl+a",description:"Toggle amend (typing)"},{key:"o",description:"Pop stash"},{key:"l",description:"Stash list modal"},{key:"b",description:"Branch picker"},{key:"X",description:"Soft reset HEAD~1"}]},{title:"History",entries:[{key:"p",description:"Cherry-pick commit"},{key:"v",description:"Revert commit"}]},{title:"Compare",entries:[{key:"b",description:"Base branch picker"},{key:"u",description:"Toggle uncommitted"}]},{title:"Diff (pane focus)",entries:[{key:"n",description:"Next hunk"},{key:"N",description:"Previous hunk"},{key:"s",description:"Toggle hunk staged/unstaged"},{key:"d",description:"Discard changes"}]}];class U8{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),q=Math.min(this.calculateHeight(X),Z-4);this.box=o9.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(X,Q)}calculateHeight($){if($){let J=Math.ceil(g.length/2),K=g.slice(0,J),Z=g.slice(J),X=K.reduce((q,z)=>q+z.entries.length+2,0),Q=Z.reduce((q,z)=>q+z.entries.length+2,0);return Math.max(X,Q)+5}else return g.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(g.length/2),X=g.slice(0,Z),Q=g.slice(Z),q=Math.floor((J-6)/2),z=this.renderGroups(X,q),V=this.renderGroups(Q,q),Y=Math.max(z.length,V.length);for(let U=0;U<Y;U++){let j=this.padToVisible(z[U]||"",q),B=V[U]||"";K.push(j+" "+B)}}else for(let Z of g){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(`
|
|
45
|
+
`)),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 r9 from"neo-blessed";class B8{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,z=Math.min(J.length,15)+6;this.box=r9.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()}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(`
|
|
46
|
+
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import a9 from"neo-blessed";class G8{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=a9.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(`
|
|
47
|
+
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import v5 from"neo-blessed";import{Fzf as s9}from"fzf";var P$=15,n9=15;function i9($,J,K){let Z="";for(let X=0;X<$.length;X++)if(J.has(X+K))Z+=`{yellow-fg}${$[X]}{/yellow-fg}`;else Z+=$[X];return Z}class j8{box;textbox;screen;allPaths;results=[];selectedIndex=0;query="";onSelect;onCancel;debounceTimer=null;fzf;constructor($,J,K,Z){this.screen=$,this.allPaths=J,this.onSelect=K,this.onCancel=Z,this.fzf=new s9(J,{limit:P$,casing:"smart-case"});let X=Math.min(80,$.width-10),Q=P$+6;this.box=v5.box({parent:$,top:"center",left:"center",width:X,height:Q,border:{type:"line"},style:{border:{fg:"cyan"}},tags:!0,keys:!1}),this.textbox=v5.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.renderContent()}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.renderContent()}),this.textbox.key(["C-k","up"],()=>{this.selectedIndex=Math.max(0,this.selectedIndex-1),this.renderContent()}),this.textbox.key(["tab"],()=>{this.selectedIndex=(this.selectedIndex+1)%Math.max(1,this.results.length),this.renderContent()}),this.textbox.key(["S-tab"],()=>{this.selectedIndex=(this.selectedIndex-1+this.results.length)%Math.max(1,this.results.length),this.renderContent()}),this.textbox.on("keypress",()=>{if(this.debounceTimer)clearTimeout(this.debounceTimer);this.debounceTimer=setTimeout(()=>{let $=this.textbox.getValue()||"";if($!==this.query)this.query=$,this.selectedIndex=0,this.updateResults(),this.renderContent()},n9)})}updateResults(){if(!this.query){this.results=this.allPaths.slice(0,P$).map((J)=>({path:J,positions:new Set,score:0}));return}let $=this.fzf.find(this.query);this.results=$.map((J)=>({path:J.item,score:J.score,positions:J.positions}))}renderContent(){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,q=J-4,z=Q,V=0;if(z.length>q)V=z.length-(q-1),z="…"+z.slice(V),V=V-1;let Y=i9(z,Z.positions,V);if(X)$.push(`{cyan-fg}{bold}> ${Y}{/bold}{/cyan-fg}`);else $.push(` ${Y}`)}while($.length<P$+3)$.push("");$.push("{gray-fg}Enter: select | Esc: cancel | Ctrl+j/k or ↑↓: navigate{/gray-fg}"),this.box.setContent($.join(`
|
|
48
|
+
`)),this.screen.render()}close(){if(this.debounceTimer)clearTimeout(this.debounceTimer);this.textbox.destroy(),this.box.destroy()}focus(){this.textbox.focus()}}import t9 from"neo-blessed";class _8{box;screen;entries;selectedIndex=0;onPop;onCancel;constructor($,J,K,Z){this.screen=$,this.entries=J,this.onPop=K,this.onCancel=Z;let X=Math.min(70,$.width-6),q=Math.min(J.length,15)+6;this.box=t9.box({parent:$,top:"center",left:"center",width:X,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"],()=>{if(this.entries.length>0){let $=this.entries[this.selectedIndex].index;this.close(),this.onPop($)}}),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.entries.length-1,this.selectedIndex+1),this.render()})}render(){let $=[],J=this.box.width-4;if($.push("{bold}{cyan-fg} Stash List{/cyan-fg}{/bold}"),$.push(""),this.entries.length===0)$.push("{gray-fg}No stash entries{/gray-fg}");else for(let K=0;K<this.entries.length;K++){let Z=this.entries[K],X=K===this.selectedIndex,Q=Z.message.length>J-10?Z.message.slice(0,J-13)+"…":Z.message;if(X)$.push(`{cyan-fg}{bold}> {${K}} ${Q}{/bold}{/cyan-fg}`);else $.push(` {gray-fg}{${K}}{/gray-fg} ${Q}`)}$.push(""),$.push("{gray-fg}j/k: navigate | Enter: pop | Esc: cancel{/gray-fg}"),this.box.setContent($.join(`
|
|
49
|
+
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import W5 from"neo-blessed";class M8{box;textbox;screen;branches;filteredBranches=[];selectedIndex=0;query="";showCreate=!1;onSwitch;onCreate;onCancel;constructor($,J,K,Z,X){this.screen=$,this.branches=J,this.onSwitch=K,this.onCreate=Z,this.onCancel=X,this.filteredBranches=J;let Q=Math.min(60,$.width-6),z=Math.min(J.length+1,15)+7;this.box=W5.box({parent:$,top:"center",left:"center",width:Q,height:z,border:{type:"line"},style:{border:{fg:"cyan"}},tags:!0,keys:!1}),this.textbox=W5.textarea({parent:this.box,top:1,left:1,width:Q-4,height:1,inputOnFocus:!0,style:{fg:"white",bg:"default"}}),this.setupKeyHandlers(),this.render()}setupKeyHandlers(){this.textbox.key(["escape"],()=>{this.close(),this.onCancel()}),this.textbox.key(["enter"],()=>{if(this.showCreate&&this.selectedIndex===0)this.close(),this.onCreate(this.query.trim());else{let $=this.showCreate?this.selectedIndex-1:this.selectedIndex,J=this.filteredBranches[$];if(J&&!J.current)this.close(),this.onSwitch(J.name)}}),this.textbox.key(["C-j","down"],()=>{let $=this.filteredBranches.length+(this.showCreate?1:0)-1;this.selectedIndex=Math.min($,this.selectedIndex+1),this.render()}),this.textbox.key(["C-k","up"],()=>{this.selectedIndex=Math.max(0,this.selectedIndex-1),this.render()}),this.textbox.on("keypress",()=>{setImmediate(()=>{let $=this.textbox.getValue()||"";if($!==this.query)this.query=$,this.selectedIndex=0,this.updateFilter(),this.render()})})}updateFilter(){let $=this.query.trim().toLowerCase();if(!$)this.filteredBranches=this.branches,this.showCreate=!1;else this.filteredBranches=this.branches.filter((J)=>J.name.toLowerCase().includes($)),this.showCreate=!this.branches.some((J)=>J.name===$)}render(){let $=[];if($.push("{bold}{cyan-fg}Switch / Create Branch{/cyan-fg}{/bold}"),$.push(""),$.push(""),this.showCreate)if(this.selectedIndex===0)$.push(`{green-fg}{bold}> Create: ${this.query.trim()}{/bold}{/green-fg}`);else $.push(` {green-fg}Create: ${this.query.trim()}{/green-fg}`);for(let J=0;J<this.filteredBranches.length;J++){let K=this.filteredBranches[J],X=(this.showCreate?J+1:J)===this.selectedIndex,Q=X?"{cyan-fg}{bold}> ":" ";if(K.current)Q+="* ";if(Q+=K.name,X)Q+="{/bold}{/cyan-fg}";if(K.current)Q+=" {gray-fg}(current){/gray-fg}";$.push(Q)}if(this.filteredBranches.length===0&&!this.showCreate)$.push("{gray-fg}No matching branches{/gray-fg}");$.push(""),$.push("{gray-fg}Enter: select | Esc: cancel | Ctrl+j/k: navigate{/gray-fg}"),this.box.setContent($.join(`
|
|
50
|
+
`)),this.screen.render()}close(){this.textbox.destroy(),this.box.destroy()}focus(){this.textbox.focus()}}import e9 from"neo-blessed";class O8{box;screen;onConfirm;onCancel;constructor($,J,K,Z){this.screen=$,this.onConfirm=K,this.onCancel=Z;let X=Math.min(60,$.width-6),Q=9;this.box=e9.box({parent:$,top:"center",left:"center",width:X,height:Q,border:{type:"line"},style:{border:{fg:"yellow"}},tags:!0,keys:!0}),this.setupKeyHandlers(),this.renderContent(J,X)}setupKeyHandlers(){this.box.key(["y","Y"],()=>{this.close(),this.onConfirm()}),this.box.key(["n","N","escape","q"],()=>{this.close(),this.onCancel()})}renderContent($,J){let K=[],Z=J-6;K.push("{bold}{yellow-fg} Soft Reset HEAD~1?{/yellow-fg}{/bold}"),K.push("");let X=$.message.length>Z?$.message.slice(0,Z-3)+"…":$.message;K.push(`{yellow-fg}${$.shortHash}{/yellow-fg} ${X}`),K.push(""),K.push("{gray-fg}Changes will return to staged state{/gray-fg}"),K.push(""),K.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(K.join(`
|
|
51
|
+
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import $3 from"neo-blessed";class S${box;screen;onConfirm;onCancel;constructor($,J,K,Z,X){this.screen=$,this.onConfirm=Z,this.onCancel=X;let Q=Math.min(60,$.width-6),q=8;this.box=$3.box({parent:$,top:"center",left:"center",width:Q,height:q,border:{type:"line"},style:{border:{fg:"yellow"}},tags:!0,keys:!0}),this.setupKeyHandlers(),this.renderContent(J,K,Q)}setupKeyHandlers(){this.box.key(["y","Y"],()=>{this.close(),this.onConfirm()}),this.box.key(["n","N","escape","q"],()=>{this.close(),this.onCancel()})}renderContent($,J,K){let Z=[],X=K-6;Z.push(`{bold}{yellow-fg} ${$} commit?{/yellow-fg}{/bold}`),Z.push("");let Q=J.message.length>X?J.message.slice(0,X-3)+"…":J.message;Z.push(`{yellow-fg}${J.shortHash}{/yellow-fg} ${Q}`),Z.push(""),Z.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(Z.join(`
|
|
52
|
+
`)),this.screen.render()}close(){this.box.destroy()}focus(){this.box.focus()}}import{EventEmitter as J3}from"node:events";function D5($,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 A5($){return $.trim()}var T5={message:"",amend:!1,isCommitting:!1,error:null,inputFocused:!1};class v8 extends J3{_state={...T5};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 $=D5(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(A5(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={...T5},this.emit("change",this._state)}}import{EventEmitter as K3}from"node:events";var Z3={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,selectedHunkIndex:0,wrapMode:!1,autoTabEnabled:!1,mouseEnabled:!0,hideHiddenFiles:!0,hideGitignored:!0,flatViewMode:!1,splitRatio:0.4,activeModal:null,pendingDiscard:null,commitInputFocused:!1};class W8 extends K3{_state;constructor($={}){super();this._state={...Z3,...$}}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,$)})}setSelectedHunkIndex($){this.update({selectedHunkIndex:Math.max(0,$)})}clampSelectedHunkIndex($){if($<=0)this._state.selectedHunkIndex=0;else if(this._state.selectedHunkIndex>=$)this._state.selectedHunkIndex=$-1}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})}toggleFlatViewMode(){this.update({flatViewMode:!this._state.flatViewMode,fileListScrollOffset:0})}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,selectedHunkIndex:0},this.emit("change",this._state)}}import*as I from"node:path";import*as m from"node:fs";import{execFileSync as V3}from"node:child_process";import{watch as P5}from"chokidar";import{EventEmitter as Y3}from"node:events";import S5 from"ignore";class N5{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 D8=new Map;function H5($){let J=D8.get($);if(!J)J=new N5,D8.set($,J);return J}function E5($){D8.delete($)}import{execSync as X3}from"node:child_process";import{simpleGit as Q$}from"simple-git";function Q3($){let J=$.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);if(J)return{oldStart:parseInt(J[1],10),newStart:parseInt(J[2],10)};return null}function b$($){let J=$.split(`
|
|
53
|
+
`);if(J.length>1&&J[J.length-1]==="")J.pop();let 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 q=Q3(Q);if(q)Z=q.oldStart,X=q.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}function A8($,J){if(!$)return null;let K=$.split(`
|
|
54
|
+
`),Z=[],X=-1;for(let Y=0;Y<K.length;Y++){if(K[Y].startsWith("@@")){X=Y;break}Z.push(K[Y])}if(X===-1)return null;let Q=-1,q=-1;for(let Y=X;Y<K.length;Y++)if(K[Y].startsWith("@@")){if(Q++,Q===J){q=Y;break}}if(q===-1)return null;let z=[K[q]];for(let Y=q+1;Y<K.length;Y++){if(K[Y].startsWith("@@")||K[Y].startsWith("diff --git"))break;z.push(K[Y])}while(z.length>1&&z[z.length-1]==="")z.pop();return[...Z,...z].join(`
|
|
50
55
|
`)+`
|
|
51
|
-
`}function
|
|
52
|
-
`))if(
|
|
53
|
-
`);
|
|
54
|
-
`),lines:
|
|
55
|
-
`)){let z=Q.exec(q);if(z){let V=z[1].split(",").map((Y)=>Y.trim());for(let Y of V){if(Y.startsWith("HEAD")||Y.startsWith("tag:")||!Y.includes("/"))continue;let U=Y.replace(/^.*-> /,"");if(U.includes("/")&&!
|
|
56
|
-
`).filter((
|
|
57
|
-
`).filter((
|
|
58
|
-
`)[0],author:
|
|
59
|
-
`).filter((O)=>O)){let O=
|
|
60
|
-
`).filter((O)=>O)){let O=
|
|
61
|
-
`)}function U5($){let J=Y5(),Z=r.resolve($);return J[Z]}function G5($,J){let Z=Y5(),K=r.resolve($);Z[K]=J,p9(Z)}class _5 extends u9{repoPath;queue;gitWatcher=null;workingDirWatcher=null;ignorers=new Map;diffDebounceTimer=null;_state={status:null,diff:null,combinedFileDiffs:null,selectedFile:null,isLoading:!1,error:null,hunkCounts: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=h0($)}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=j5();J.add(".git");let Z=I.join(this.repoPath,".gitignore");if(m.existsSync(Z))J.add(m.readFileSync(Z,"utf-8"));let K=I.join(this.repoPath,".git","info","exclude");if(m.existsSync(K))J.add(m.readFileSync(K,"utf-8"));$.set("",J);try{let X=g9("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 q=I.dirname(Q),z=I.join(this.repoPath,Q);try{let V=m.readFileSync(z,"utf-8"),Y=j5();Y.add(V),$.set(q,Y)}catch{}}}catch{}return $}startWatching(){let $=I.join(this.repoPath,".git");if(!m.existsSync($))return;let J=I.join($,"index"),Z=I.join($,"HEAD"),K=I.join($,"refs"),X=I.join(this.repoPath,".gitignore");this.gitWatcher=B5([J,Z,K,X],{persistent:!0,ignoreInitial:!0,usePolling:!0,interval:100}),this.ignorers=this.loadGitignores(),this.workingDirWatcher=B5(this.repoPath,{persistent:!0,ignoreInitial:!0,ignored:(q)=>{let z=I.relative(this.repoPath,q);if(!z)return!1;let V=z.split("/");for(let Y=0;Y<V.length;Y++){let U=Y===0?"":V.slice(0,Y).join("/"),j=this.ignorers.get(U);if(j){let G=Y===0?z:V.slice(Y).join("/");if(j.ignores(G))return!0}}return!1},awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}});let Q=()=>this.scheduleRefresh();this.gitWatcher.on("change",(q)=>{if(q===X)this.ignorers=this.loadGitignores();Q()}),this.gitWatcher.on("add",Q),this.gitWatcher.on("unlink",Q),this.gitWatcher.on("error",(q)=>{let z=q instanceof Error?q.message:String(q);this.emit("error",`Git watcher error: ${z}`)}),this.workingDirWatcher.on("change",Q),this.workingDirWatcher.on("add",Q),this.workingDirWatcher.on("unlink",Q),this.workingDirWatcher.on("error",(q)=>{let z=q instanceof Error?q.message:String(q);this.emit("error",`Working dir watcher error: ${z}`)})}dispose(){if(this.diffDebounceTimer)clearTimeout(this.diffDebounceTimer);this.gitWatcher?.close(),this.workingDirWatcher?.close(),c0(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 M8(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 M8(this.repoPath);if(!$.isRepo){this.updateState({status:$,diff:null,isLoading:!1,error:"Not a git repository"});return}let[J,Z]=await Promise.all([u(this.repoPath,void 0,!1),u(this.repoPath,void 0,!0)]),K={unstaged:v8(J.raw),staged:v8(Z.raw)},{displayDiff:X,combinedFileDiffs:Q}=await this.resolveFileDiffs($,J);this.updateState({status:$,diff:X,combinedFileDiffs:Q,hunkCounts:K,isLoading:!1})}catch($){this.updateState({isLoading:!1,error:$ instanceof Error?$.message:"Unknown error"})}}async resolveFileDiffs($,J){let Z=this._state.selectedFile;if(!Z)return{displayDiff:J,combinedFileDiffs:null};let K=$.files.find((z)=>z.path===Z.path&&z.staged===Z.staged)??$.files.find((z)=>z.path===Z.path);if(!K)return this.updateState({selectedFile:null}),{displayDiff:J,combinedFileDiffs:null};if(K.status==="untracked"){let z=await W8(this.repoPath,K.path);return{displayDiff:z,combinedFileDiffs:{unstaged:z,staged:{raw:"",lines:[]}}}}let[X,Q]=await Promise.all([u(this.repoPath,K.path,!1),u(this.repoPath,K.path,!0)]);return{displayDiff:K.staged?Q:X,combinedFileDiffs:{unstaged:X,staged:Q}}}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;await this.doFetchDiffForFile($)}).catch((J)=>{this.updateState({error:`Failed to load diff: ${J instanceof Error?J.message:String(J)}`})})}async doFetchDiffForFile($){if(!$){let K=await Q5(this.repoPath);if(this._state.selectedFile===null)this.updateState({diff:K,combinedFileDiffs:null});return}if($.status==="untracked"){let K=await W8(this.repoPath,$.path);if($===this._state.selectedFile)this.updateState({diff:K,combinedFileDiffs:{unstaged:K,staged:{raw:"",lines:[]}}});return}let[J,Z]=await Promise.all([u(this.repoPath,$.path,!1),u(this.repoPath,$.path,!0)]);if($===this._state.selectedFile){let K=$.staged?Z:J;this.updateState({diff:K,combinedFileDiffs:{unstaged:J,staged:Z}})}}async stage($){try{await this.queue.enqueueMutation(()=>s0(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(()=>n0(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 stageHunk($){try{await this.queue.enqueueMutation(async()=>Z5(this.repoPath,$)),this.scheduleRefresh()}catch(J){await this.refresh(),this.updateState({error:`Failed to stage hunk: ${J instanceof Error?J.message:String(J)}`})}}async unstageHunk($){try{await this.queue.enqueueMutation(async()=>K5(this.repoPath,$)),this.scheduleRefresh()}catch(J){await this.refresh(),this.updateState({error:`Failed to unstage hunk: ${J instanceof Error?J.message:String(J)}`})}}async discard($){if($.staged||$.status==="untracked")return;try{await this.queue.enqueueMutation(()=>e0(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(()=>i0(this.repoPath)),await this.refresh()}catch($){this.updateState({error:`Failed to stage all: ${$ instanceof Error?$.message:String($)}`})}}async unstageAll(){try{await this.queue.enqueueMutation(()=>t0(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(()=>$5(this.repoPath,$,J)),await this.refresh()}catch(Z){this.updateState({error:`Failed to commit: ${Z instanceof Error?Z.message:String(Z)}`})}}async getHeadCommitMessage(){return this.queue.enqueue(()=>J5(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=U5(this.repoPath)??await q5(this.repoPath),this.updateCompareState({compareBaseBranch:J});if(J){let Z=$?await z5(this.repoPath,J):await D8(this.repoPath,J);this.updateCompareState({compareDiff:Z,compareLoading:!1})}else this.updateCompareState({compareDiff:null,compareLoading:!1,compareError:"No base branch found"})}async getCandidateBaseBranches(){return A8(this.repoPath)}async setCompareBaseBranch($,J=!1){this.updateCompareState({compareBaseBranch:$}),G5(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 X5(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 T8(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 Z=J.commits[$];this.updateCompareSelectionState({type:"commit",index:$,diff:null});try{await this.queue.enqueue(async()=>{let K=await T8(this.repoPath,Z.hash);this.updateCompareSelectionState({diff:K})})}catch(K){this.updateState({error:`Failed to load commit diff: ${K instanceof Error?K.message:String(K)}`})}}selectCompareFile($){let J=this._compareState.compareDiff;if(!J||$<0||$>=J.files.length){this.updateCompareSelectionState({type:null,index:0,diff:null});return}let Z=J.files[$];this.updateCompareSelectionState({type:"file",index:$,diff:Z.diff})}}var w$=new Map;function M5($){let J=w$.get($);if(!J)J=new _5($),w$.set($,J);return J}function N8($){let J=w$.get($);if(J)J.dispose(),w$.delete($)}class H8{screen;layout;uiState;gitManager=null;followMode=null;explorerManager=null;config;commandServer;repoPath;currentTheme;commitFlowState;commitTextarea=null;activeModal=null;bottomPaneTotalRows=0;bottomPaneHunkCount=0;bottomPaneHunkBoundaries=[];pendingSelectionAnchor=null;cachedFlatFiles=[];pendingFlatSelectionPath=null;pendingHunkIndex=null;combinedHunkMapping=[];constructor($){this.config=$.config,this.commandServer=$.commandServer??null,this.repoPath=$.initialPath??process.cwd(),this.currentTheme=$.config.theme,this.uiState=new j8({splitRatio:$.config.splitRatio??0.4}),this.screen=O5.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 p$(this.screen,this.uiState.state.splitRatio),this.screen.on("resize",()=>{setImmediate(()=>this.render())}),this.commitFlowState=new B8({getHeadMessage:()=>this.gitManager?.getHeadCommitMessage()??Promise.resolve(""),onCommit:async(Z,K)=>{await this.gitManager?.commit(Z,K)},onSuccess:()=>{this.uiState.setTab("diff"),this.render()}}),this.commitTextarea=O5.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 Z=this.commitTextarea?.getValue()??"";this.commitFlowState.setMessage(Z)})}),this.setupKeyboardHandlers(),this.setupMouseEventHandlers(),this.setupStateListeners(),this.config.watcherEnabled)this.followMode=new C$(this.config.targetFile,()=>this.repoPath,{onRepoChange:(Z,K)=>this.handleFollowRepoChange(Z,K),onFileNavigate:(Z)=>this.handleFollowFileNavigate(Z)}),this.followMode.start();if(this.commandServer)this.setupCommandHandler();this.initGitManager(),this.render()}setupKeyboardHandlers(){P8(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(),toggleCurrentHunk:()=>this.toggleCurrentHunk(),navigateNextHunk:()=>this.navigateNextHunk(),navigatePrevHunk:()=>this.navigatePrevHunk()},{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,getExplorerManager:()=>this.explorerManager,commitFlowState:this.commitFlowState,getGitManager:()=>this.gitManager,layout:this.layout,getCachedFlatFiles:()=>this.cachedFlatFiles})}setupMouseEventHandlers(){F0(this.layout,{selectHistoryCommitByIndex:($)=>this.selectHistoryCommitByIndex($),selectCompareItem:($)=>this.selectCompareItem($),selectFileByIndex:($)=>this.selectFileByIndex($),toggleFileByIndex:($)=>this.toggleFileByIndex($),enterExplorerDirectory:()=>this.enterExplorerDirectory(),toggleMouseMode:()=>this.toggleMouseMode(),toggleFollow:()=>this.toggleFollow(),selectHunkAtRow:($)=>this.selectHunkAtRow($),render:()=>this.render()},{uiState:this.uiState,getExplorerManager:()=>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,getCachedFlatFiles:()=>this.cachedFlatFiles})}async toggleFlatEntry($){if(this.pendingFlatSelectionPath=$.path,$.stagingState==="staged"){if($.stagedEntry)await this.gitManager?.unstage($.stagedEntry)}else if($.unstagedEntry)await this.gitManager?.stage($.unstagedEntry)}async toggleFileByIndex($){if(this.uiState.state.flatViewMode){let J=w(this.cachedFlatFiles,$);if(J)await this.toggleFlatEntry(J)}else{let J=this.gitManager?.state.status?.files??[],Z=b(J,$);if(Z)if(this.pendingSelectionAnchor=s(J,this.uiState.state.selectedIndex),Z.staged)await this.gitManager?.unstage(Z);else await this.gitManager?.stage(Z)}}setupStateListeners(){this.uiState.on("change",()=>{this.render()}),this.uiState.on("tab-change",(J)=>{if(J!=="diff")this.uiState.setSelectedHunkIndex(0);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 z8(this.screen,this.currentTheme,(Z)=>{this.currentTheme=Z,Z8({theme:Z}),this.activeModal=null,this.uiState.closeModal(),this.render()},()=>{this.activeModal=null,this.uiState.closeModal()}),this.activeModal.focus();else if(J==="hotkeys")this.activeModal=new V8(this.screen,()=>{this.activeModal=null,this.uiState.closeModal()}),this.activeModal.focus();else if(J==="baseBranch")this.gitManager?.getCandidateBaseBranches().then((Z)=>{let K=this.gitManager?.compareState.compareBaseBranch??null;this.activeModal=new Y8(this.screen,Z,K,(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)Z8({splitRatio:J.splitRatio})},500)})}handleFollowRepoChange($,J){let Z=this.repoPath;this.repoPath=$,this.initGitManager(Z),this.resetRepoSpecificState(),this.loadCurrentTabData(),this.render()}handleFollowFileNavigate($){this.navigateToFile($),this.render()}initGitManager($){if(this.gitManager)this.gitManager.removeAllListeners(),N8($??this.repoPath);this.gitManager=M5(this.repoPath),this.gitManager.on("state-change",()=>{if(!this.gitManager?.state.isLoading)this.reconcileSelectionAfterStateChange();this.updateExplorerGitStatus(),this.render()}),this.gitManager.on("history-state-change",(J)=>{if(J.commits.length>0&&!J.selectedCommit){let Z=this.uiState.state;if(Z.bottomTab==="history")this.selectHistoryCommitByIndex(Z.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()}reconcileSelectionAfterStateChange(){let $=this.gitManager?.state.status?.files??[];if(this.uiState.state.flatViewMode&&this.pendingFlatSelectionPath){let J=M$($,this.gitManager?.state.hunkCounts??null),Z=this.pendingFlatSelectionPath;this.pendingFlatSelectionPath=null;let K=y8(J,Z);if(K>=0)this.uiState.setSelectedIndex(K),this.selectFileByIndex(K);else if(J.length>0){let X=Math.min(this.uiState.state.selectedIndex,J.length-1);this.uiState.setSelectedIndex(X),this.selectFileByIndex(X)}return}if(this.pendingSelectionAnchor){let J=this.pendingSelectionAnchor;this.pendingSelectionAnchor=null;let Z=L8($,J.category,J.categoryIndex);this.uiState.setSelectedIndex(Z),this.selectFileByIndex(Z);return}if(this.uiState.state.flatViewMode){let Z=M$($,this.gitManager?.state.hunkCounts??null).length-1;if(Z>=0&&this.uiState.state.selectedIndex>Z)this.uiState.setSelectedIndex(Z)}else if($.length>0){let J=$.length-1;if(this.uiState.state.selectedIndex>J)this.uiState.setSelectedIndex(J)}}initExplorerManager(){if(this.explorerManager)this.explorerManager.dispose();let $={hideHidden:!0,hideGitignored:!0,showOnlyChanges:!1};this.explorerManager=new q8(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 Z of $){J.files.set(Z.path,{status:Z.status,staged:Z.staged});let K=Z.path.split("/"),X="";for(let Q=0;Q<K.length-1;Q++)X=X?`${X}/${K[Q]}`:K[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,Z=this.gitManager?.historyState,K=J?.status?.files??[],X=Z?.commits??[];return{currentTab:$.bottomTab,currentPane:$.currentPane,selectedIndex:$.selectedIndex,totalFiles:K.length,stagedCount:K.filter((Q)=>Q.staged).length,files:K.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}}scrollActiveDiffPane($){let J=this.uiState.state;if(J.bottomTab==="explorer"){let Z=Math.max(0,J.explorerFileScrollOffset+$);this.uiState.setExplorerFileScrollOffset(Z)}else{let Z=Math.max(0,J.diffScrollOffset+$);this.uiState.setDiffScrollOffset(Z)}}navigateFileList($){let J=this.uiState.state,Z=this.gitManager?.state.status?.files??[],K=J.flatViewMode?this.cachedFlatFiles.length-1:Z.length-1;if(K<0)return;let X=$===-1?Math.max(0,J.selectedIndex-1):Math.min(K,J.selectedIndex+1);this.uiState.setSelectedIndex(X),this.selectFileByIndex(X);let Q=J.flatViewMode?X+1:C8(X,Z);this.scrollToKeepRowVisible(Q,$,J.fileListScrollOffset)}scrollToKeepRowVisible($,J,Z){if(J===-1&&$<Z)this.uiState.setFileListScrollOffset($);else if(J===1){let K=Z+this.layout.dimensions.topPaneHeight-1;if($>=K)this.uiState.setFileListScrollOffset(Z+($-K+1))}}navigateActiveList($){let J=this.uiState.state.bottomTab;if(J==="history")if($===-1)this.navigateHistoryUp();else this.navigateHistoryDown();else if(J==="compare")if($===-1)this.navigateCompareUp();else this.navigateCompareDown();else if(J==="explorer")if($===-1)this.navigateExplorerUp();else this.navigateExplorerDown();else this.navigateFileList($)}navigateUp(){if(this.uiState.state.currentPane!=="diff")this.navigateActiveList(-1);else this.scrollActiveDiffPane(-3)}navigateDown(){if(this.uiState.state.currentPane!=="diff")this.navigateActiveList(1);else this.scrollActiveDiffPane(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??[],Z=Math.min(J.length-1,$.historySelectedIndex+1);if(Z!==$.historySelectedIndex){this.uiState.setHistorySelectedIndex(Z);let K=$.historyScrollOffset+this.layout.dimensions.topPaneHeight-1;if(Z>=K)this.uiState.setHistoryScrollOffset($.historyScrollOffset+1);this.selectHistoryCommitByIndex(Z)}}selectHistoryCommitByIndex($){let J=this.gitManager?.historyState.commits??[],Z=p8(J,$);if(Z)this.uiState.setDiffScrollOffset(0),this.gitManager?.selectHistoryCommit(Z)}compareSelection=null;navigateCompareUp(){let $=this.gitManager?.compareState,J=$?.compareDiff?.commits??[],Z=$?.compareDiff?.files??[];if(J.length===0&&Z.length===0)return;let K=l$(this.compareSelection,J,Z,"up");if(K&&(K.type!==this.compareSelection?.type||K.index!==this.compareSelection?.index)){this.selectCompareItem(K);let X=this.uiState.state,Q=W$(K,J,Z);if(Q<X.compareScrollOffset)this.uiState.setCompareScrollOffset(Q)}}navigateCompareDown(){let $=this.gitManager?.compareState,J=$?.compareDiff?.commits??[],Z=$?.compareDiff?.files??[];if(J.length===0&&Z.length===0)return;if(!this.compareSelection){if(J.length>0)this.selectCompareItem({type:"commit",index:0});else if(Z.length>0)this.selectCompareItem({type:"file",index:0});return}let K=l$(this.compareSelection,J,Z,"down");if(K&&(K.type!==this.compareSelection?.type||K.index!==this.compareSelection?.index)){this.selectCompareItem(K);let X=this.uiState.state,Q=W$(K,J,Z),q=X.compareScrollOffset+this.layout.dimensions.topPaneHeight-1;if(Q>=q)this.uiState.setCompareScrollOffset(X.compareScrollOffset+(Q-q+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 Z=this.explorerManager?.navigateUp($.explorerScrollOffset);if(Z!==null&&Z!==void 0)this.uiState.setExplorerScrollOffset(Z);this.uiState.setExplorerSelectedIndex(this.explorerManager?.state.selectedIndex??0)}navigateExplorerDown(){let $=this.uiState.state;if((this.explorerManager?.state.displayRows??[]).length===0)return;let Z=this.layout.dimensions.topPaneHeight,K=this.explorerManager?.navigateDown($.explorerScrollOffset,Z);if(K!==null&&K!==void 0)this.uiState.setExplorerScrollOffset(K);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($){if(this.uiState.state.flatViewMode){let J=w(this.cachedFlatFiles,$);if(J){let Z=J.unstagedEntry??J.stagedEntry;if(Z)this.uiState.setDiffScrollOffset(0),this.uiState.setSelectedHunkIndex(0),this.gitManager?.selectFile(Z)}}else{let J=this.gitManager?.state.status?.files??[],Z=b(J,$);if(Z)this.uiState.setDiffScrollOffset(0),this.uiState.setSelectedHunkIndex(0),this.gitManager?.selectFile(Z)}}navigateToFile($){if(!$||!this.repoPath)return;let J=this.repoPath.endsWith("/")?this.repoPath:this.repoPath+"/";if(!$.startsWith(J))return;let Z=$.slice(J.length);if(!Z)return;let X=(this.gitManager?.state.status?.files??[]).findIndex((Q)=>Q.path===Z);if(X>=0)this.uiState.setSelectedIndex(X),this.selectFileByIndex(X)}async stageSelected(){let $=this.gitManager?.state.status?.files??[],J=this.uiState.state.selectedIndex;if(this.uiState.state.flatViewMode){let Z=w(this.cachedFlatFiles,J);if(!Z)return;let K=Z.unstagedEntry;if(K)this.pendingFlatSelectionPath=Z.path,await this.gitManager?.stage(K)}else{let Z=b($,J);if(Z&&!Z.staged)this.pendingSelectionAnchor=s($,J),await this.gitManager?.stage(Z)}}async unstageSelected(){let $=this.gitManager?.state.status?.files??[],J=this.uiState.state.selectedIndex;if(this.uiState.state.flatViewMode){let Z=w(this.cachedFlatFiles,J);if(!Z)return;let K=Z.stagedEntry;if(K)this.pendingFlatSelectionPath=Z.path,await this.gitManager?.unstage(K)}else{let Z=b($,J);if(Z?.staged)this.pendingSelectionAnchor=s($,J),await this.gitManager?.unstage(Z)}}async toggleSelected(){let $=this.uiState.state.selectedIndex;if(this.uiState.state.flatViewMode){let J=w(this.cachedFlatFiles,$);if(J)await this.toggleFlatEntry(J)}else{let J=this.gitManager?.state.status?.files??[],Z=b(J,$);if(Z)if(this.pendingSelectionAnchor=s(J,$),Z.staged)await this.gitManager?.unstage(Z);else await this.gitManager?.stage(Z)}}async stageAll(){await this.gitManager?.stageAll()}async unstageAll(){await this.gitManager?.unstageAll()}showDiscardConfirm($){this.activeModal=new U8(this.screen,$.path,async()=>{this.activeModal=null,await this.gitManager?.discard($)},()=>{this.activeModal=null}),this.activeModal.focus()}navigateNextHunk(){let $=this.uiState.state.selectedHunkIndex;if(this.bottomPaneHunkCount>0&&$<this.bottomPaneHunkCount-1)this.uiState.setSelectedHunkIndex($+1),this.scrollHunkIntoView($+1)}navigatePrevHunk(){let $=this.uiState.state.selectedHunkIndex;if($>0)this.uiState.setSelectedHunkIndex($-1),this.scrollHunkIntoView($-1)}scrollHunkIntoView($){let J=this.bottomPaneHunkBoundaries[$];if(!J)return;let Z=this.uiState.state.diffScrollOffset,K=this.layout.dimensions.bottomPaneHeight;if(J.startRow<Z||J.startRow>=Z+K)this.uiState.setDiffScrollOffset(J.startRow)}selectHunkAtRow($){if(this.uiState.state.bottomTab!=="diff")return;if(this.bottomPaneHunkBoundaries.length===0)return;this.uiState.setPane("diff");let J=this.uiState.state.diffScrollOffset+$;for(let Z=0;Z<this.bottomPaneHunkBoundaries.length;Z++){let K=this.bottomPaneHunkBoundaries[Z];if(J>=K.startRow&&J<K.endRow){this.uiState.setSelectedHunkIndex(Z);return}}}async toggleCurrentHunk(){let $=this.gitManager?.state.selectedFile;if(!$||$.status==="untracked")return;if(this.uiState.state.flatViewMode)await this.toggleCurrentHunkFlat();else await this.toggleCurrentHunkCategorized($)}async toggleCurrentHunkFlat(){let $=this.combinedHunkMapping[this.uiState.state.selectedHunkIndex];if(!$)return;let J=this.gitManager?.state.combinedFileDiffs;if(!J)return;let Z=$.source==="unstaged"?J.unstaged.raw:J.staged.raw,K=O8(Z,$.hunkIndex);if(!K)return;if(this.pendingHunkIndex=this.uiState.state.selectedHunkIndex,$.source==="staged")await this.gitManager?.unstageHunk(K);else await this.gitManager?.stageHunk(K)}async toggleCurrentHunkCategorized($){let J=this.gitManager?.state.diff?.raw;if(!J)return;let Z=O8(J,this.uiState.state.selectedHunkIndex);if(!Z)return;let K=this.gitManager?.state.status?.files??[];if(this.pendingSelectionAnchor=s(K,this.uiState.state.selectedIndex),$.staged)await this.gitManager?.unstageHunk(Z);else await this.gitManager?.stageHunk(Z)}async openFileFinder(){let $=await this.explorerManager?.getAllFilePaths()??[];if($.length===0)return;this.activeModal=new G8(this.screen,$,async(J)=>{if(this.activeModal=null,this.uiState.state.bottomTab!=="explorer")this.uiState.setTab("explorer");if(await this.explorerManager?.navigateToPath(J)){let K=this.explorerManager?.state.selectedIndex??0;this.uiState.setExplorerSelectedIndex(K),this.uiState.setExplorerFileScrollOffset(0);let X=this.layout.dimensions.topPaneHeight;if(K>=X)this.uiState.setExplorerScrollOffset(K-Math.floor(X/2));else this.uiState.setExplorerScrollOffset(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 C$(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(){if(this.updateHeader(),this.updateTopPane(),this.updateBottomPane(),this.pendingHunkIndex!==null&&this.bottomPaneHunkCount>0){let $=Math.min(this.pendingHunkIndex,this.bottomPaneHunkCount-1);this.pendingHunkIndex=null,this.uiState.setSelectedHunkIndex($),this.updateBottomPane()}this.updateFooter(),this.screen.render()}updateHeader(){let $=this.gitManager?.state,J=this.screen.width||80,Z=b0(this.repoPath,$?.status?.branch??null,$?.isLoading??!1,$?.error??null,J);this.layout.headerBox.setContent(Z)}updateTopPane(){let $=this.uiState.state,J=this.screen.width||80,Z=this.gitManager?.state.status?.files??[];if($.flatViewMode)this.cachedFlatFiles=M$(Z,this.gitManager?.state.hunkCounts??null);let K=E0($,Z,this.gitManager?.historyState?.commits??[],this.gitManager?.compareState?.compareDiff??null,this.compareSelection,this.explorerManager?.state,J,this.layout.dimensions.topPaneHeight,this.gitManager?.state.hunkCounts,$.flatViewMode?this.cachedFlatFiles:void 0);this.layout.topPane.setContent(K)}updateBottomPane(){let $=this.uiState.state,J=this.screen.width||80,K=(this.gitManager?.state.status?.files??[]).filter((G)=>G.staged).length;this.commitFlowState.setStagedCount(K);let X=$.bottomTab==="diff"&&$.currentPane==="diff",Q=X?$.selectedHunkIndex:void 0,q=X?this.gitManager?.state.selectedFile?.staged:void 0,{content:z,totalRows:V,hunkCount:Y,hunkBoundaries:U,hunkMapping:j}=k0($,this.gitManager?.state.diff??null,this.gitManager?.historyState,this.gitManager?.compareSelectionState,this.explorerManager?.state?.selectedFile??null,this.commitFlowState.state,K,this.currentTheme,J,this.layout.dimensions.bottomPaneHeight,Q,q,$.flatViewMode?this.gitManager?.state.combinedFileDiffs:void 0);if(this.bottomPaneTotalRows=V,this.bottomPaneHunkCount=Y,this.bottomPaneHunkBoundaries=U,this.combinedHunkMapping=j??[],this.uiState.clampSelectedHunkIndex(Y),this.layout.bottomPane.setContent(z),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,Z=x0($.bottomTab,$.mouseEnabled,$.autoTabEnabled,$.wrapMode,this.followMode?.isEnabled??!1,this.explorerManager?.showOnlyChanges??!1,J,$.currentPane);this.layout.footerBox.setContent(Z)}exit(){if(this.gitManager)N8(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 v5 from"net";import*as f from"fs";import{EventEmitter as m9}from"events";class E8 extends m9{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(f.existsSync(this.socketPath))f.unlinkSync(this.socketPath);return new Promise(($,J)=>{this.server=v5.createServer((Z)=>{this.handleConnection(Z)}),this.server.on("error",(Z)=>{J(Z)}),this.server.listen(this.socketPath,()=>{f.chmodSync(this.socketPath,384),$()})})}stop(){if(this.server)this.server.close(),this.server=null;if(f.existsSync(this.socketPath))f.unlinkSync(this.socketPath)}handleConnection($){let J="";$.on("data",async(Z)=>{J+=Z.toString();let K=J.split(`
|
|
62
|
-
`);J=
|
|
63
|
-
`)}}),$.on("error",(
|
|
56
|
+
`}function T8($){let J=new Map;if(!$)return J;let K=null;for(let Z of $.split(`
|
|
57
|
+
`))if(Z.startsWith("diff --git")){let X=Z.match(/^diff --git a\/.+ b\/(.+)$/);if(X){if(K=X[1],!J.has(K))J.set(K,0)}}else if(Z.startsWith("@@")&&K)J.set(K,(J.get(K)??0)+1);return J}async function u($,J,K=!1){let Z=Q$($);try{let X=[];if(K)X.push("--cached");if(J)X.push("--",J);let Q=await Z.diff(X),q=b$(Q);return{raw:Q,lines:q}}catch{return{raw:"",lines:[]}}}async function N8($,J){try{let K=X3(`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(`
|
|
58
|
+
`);Z.push({type:"hunk",content:`@@ -0,0 +1,${X.length} @@`});let Q=1;for(let z of X)Z.push({type:"addition",content:"+"+z,newLineNum:Q++});return{raw:Z.map((z)=>z.content).join(`
|
|
59
|
+
`),lines:Z}}catch{return{raw:"",lines:[]}}}async function k5($){return u($,void 0,!0)}async function H8($){let J=Q$($),K=new Set,Z=[];try{let X=await J.raw(["log","--oneline","--decorate=short","--all","-n","200"]),Q=/\(([^)]+)\)/g;for(let q of X.split(`
|
|
60
|
+
`)){let z=Q.exec(q);if(z){let V=z[1].split(",").map((Y)=>Y.trim());for(let Y of V){if(Y.startsWith("HEAD")||Y.startsWith("tag:")||!Y.includes("/"))continue;let U=Y.replace(/^.*-> /,"");if(U.includes("/")&&!K.has(U))K.add(U),Z.push(U)}}Q.lastIndex=0}if(Z.length>0)Z.sort((q,z)=>{let V=q.split("/").slice(1).join("/"),Y=z.split("/").slice(1).join("/"),U=V==="main"||V==="master",j=Y==="main"||Y==="master";if(U&&!j)return-1;if(!U&&j)return 1;if(U&&j){let B=q.startsWith("origin/"),G=z.startsWith("origin/");if(B&&!G)return 1;if(!B&&G)return-1}return 0})}catch{}return[...new Set(Z)]}async function R5($){return(await H8($))[0]??null}async function E8($,J){let K=Q$($),X=(await K.raw(["merge-base",J,"HEAD"])).trim(),Q=await K.raw(["diff","--numstat",`${X}...HEAD`]),q=await K.raw(["diff","--name-status",`${X}...HEAD`]),z=await K.raw(["diff",`${X}...HEAD`]),V=Q.trim().split(`
|
|
61
|
+
`).filter((_)=>_),Y=new Map;for(let _ of V){let O=_.split("\t");if(O.length>=3){let D=O[0]==="-"?0:parseInt(O[0],10),k=O[1]==="-"?0:parseInt(O[1],10),H=O.slice(2).join("\t");Y.set(H,{additions:D,deletions:k})}}let U=q.trim().split(`
|
|
62
|
+
`).filter((_)=>_),j=new Map;for(let _ of U){let O=_.split("\t");if(O.length>=2){let D=O[0][0],k=O[O.length-1],H;switch(D){case"A":H="added";break;case"D":H="deleted";break;case"R":H="renamed";break;default:H="modified"}j.set(k,H)}}let B=[],G=z.split(/(?=^diff --git )/m).filter((_)=>_.trim());for(let _ of G){let O=_.match(/^diff --git a\/.+ b\/(.+)$/m);if(!O)continue;let D=O[1],k=b$(_),H=Y.get(D)||{additions:0,deletions:0},R=j.get(D)||"modified";B.push({path:D,status:R,additions:H.additions,deletions:H.deletions,diff:{raw:_,lines:k}})}let M=0,v=0;for(let _ of B)M+=_.additions,v+=_.deletions;let A=(await K.status()).files.length,N=(await K.log({from:X,to:"HEAD"})).all.map((_)=>({hash:_.hash,shortHash:_.hash.slice(0,7),message:_.message.split(`
|
|
63
|
+
`)[0],author:_.author_name,date:new Date(_.date),refs:_.refs||""}));return B.sort((_,O)=>_.path.localeCompare(O.path)),{baseBranch:J,stats:{filesChanged:B.length,additions:M,deletions:v},files:B,commits:N,uncommittedCount:A}}async function k8($,J){let K=Q$($);try{let Z=await K.raw(["show",J,"--format="]),X=b$(Z);return{raw:Z,lines:X}}catch{return{raw:"",lines:[]}}}async function L5($,J){let K=Q$($),Z=await E8($,J),X=await K.diff(["--cached","--numstat"]),Q=await K.diff(["--numstat"]),q=await K.diff(["--cached"]),z=await K.diff([]),V=new Map;for(let _ of X.trim().split(`
|
|
64
|
+
`).filter((O)=>O)){let O=_.split("\t");if(O.length>=3){let D=O[0]==="-"?0:parseInt(O[0],10),k=O[1]==="-"?0:parseInt(O[1],10),H=O.slice(2).join("\t");V.set(H,{additions:D,deletions:k,staged:!0,unstaged:!1})}}for(let _ of Q.trim().split(`
|
|
65
|
+
`).filter((O)=>O)){let O=_.split("\t");if(O.length>=3){let D=O[0]==="-"?0:parseInt(O[0],10),k=O[1]==="-"?0:parseInt(O[1],10),H=O.slice(2).join("\t"),R=V.get(H);if(R)R.additions+=D,R.deletions+=k,R.unstaged=!0;else V.set(H,{additions:D,deletions:k,staged:!1,unstaged:!0})}}let Y=await K.status(),U=new Map;for(let _ of Y.files)if(_.index==="A"||_.working_dir==="?")U.set(_.path,"added");else if(_.index==="D"||_.working_dir==="D")U.set(_.path,"deleted");else if(_.index==="R")U.set(_.path,"renamed");else U.set(_.path,"modified");let j=[],G=(q+z).split(/(?=^diff --git )/m).filter((_)=>_.trim()),M=new Set;for(let _ of G){let O=_.match(/^diff --git a\/.+ b\/(.+)$/m);if(!O)continue;let D=O[1];if(M.has(D))continue;M.add(D);let k=b$(_),H=V.get(D)||{additions:0,deletions:0},R=U.get(D)||"modified";j.push({path:D,status:R,additions:H.additions,deletions:H.deletions,diff:{raw:_,lines:k},isUncommitted:!0})}let v=new Set(Z.files.map((_)=>_.path)),W=[];for(let _ of Z.files){let O=j.find((D)=>D.path===_.path);if(O)W.push(_),W.push(O);else W.push(_)}for(let _ of j)if(!v.has(_.path))W.push(_);let A=0,T=0,N=new Set;for(let _ of W)N.add(_.path),A+=_.additions,T+=_.deletions;return W.sort((_,O)=>_.path.localeCompare(O.path)),{baseBranch:Z.baseBranch,stats:{filesChanged:N.size,additions:A,deletions:T},files:W,commits:Z.commits,uncommittedCount:Z.uncommittedCount}}import*as S from"node:fs";import*as o from"node:path";import*as F5 from"node:os";var w$=o.join(F5.homedir(),".cache","diffstalker","base-branches.json");function q3(){let $=o.dirname(w$);if(!S.existsSync($))S.mkdirSync($,{recursive:!0})}function I5(){try{if(S.existsSync(w$))return JSON.parse(S.readFileSync(w$,"utf-8"))}catch{}return{}}function z3($){q3(),S.writeFileSync(w$,JSON.stringify($,null,2)+`
|
|
66
|
+
`)}function y5($){let J=I5(),K=o.resolve($);return J[K]}function C5($,J){let K=I5(),Z=o.resolve($);K[Z]=J,z3(K)}class b5 extends Y3{repoPath;queue;gitWatcher=null;workingDirWatcher=null;ignorers=new Map;diffDebounceTimer=null;_state={status:null,diff:null,combinedFileDiffs:null,selectedFile:null,isLoading:!1,error:null,hunkCounts:null,stashList:[]};_compareState={compareDiff:null,compareBaseBranch:null,compareLoading:!1,compareError:null};_historyState={commits:[],selectedCommit:null,commitDiff:null,isLoading:!1};_compareSelectionState={type:null,index:0,diff:null};_remoteState={operation:null,inProgress:!1,error:null,lastResult:null};constructor($){super();this.repoPath=$,this.queue=H5($)}get state(){return this._state}get compareState(){return this._compareState}get historyState(){return this._historyState}get compareSelectionState(){return this._compareSelectionState}get remoteState(){return this._remoteState}updateRemoteState($){this._remoteState={...this._remoteState,...$},this.emit("remote-state-change",this._remoteState)}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=S5();J.add(".git");let K=I.join(this.repoPath,".gitignore");if(m.existsSync(K))J.add(m.readFileSync(K,"utf-8"));let Z=I.join(this.repoPath,".git","info","exclude");if(m.existsSync(Z))J.add(m.readFileSync(Z,"utf-8"));$.set("",J);try{let X=V3("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 q=I.dirname(Q),z=I.join(this.repoPath,Q);try{let V=m.readFileSync(z,"utf-8"),Y=S5();Y.add(V),$.set(q,Y)}catch{}}}catch{}return $}startWatching(){let $=I.join(this.repoPath,".git");if(!m.existsSync($))return;let J=I.join($,"index"),K=I.join($,"HEAD"),Z=I.join($,"refs"),X=I.join(this.repoPath,".gitignore");this.gitWatcher=P5([J,K,Z,X],{persistent:!0,ignoreInitial:!0,usePolling:!0,interval:100}),this.ignorers=this.loadGitignores(),this.workingDirWatcher=P5(this.repoPath,{persistent:!0,ignoreInitial:!0,ignored:(q)=>{let z=I.relative(this.repoPath,q);if(!z)return!1;let V=z.split("/");for(let Y=0;Y<V.length;Y++){let U=Y===0?"":V.slice(0,Y).join("/"),j=this.ignorers.get(U);if(j){let B=Y===0?z:V.slice(Y).join("/");if(j.ignores(B))return!0}}return!1},awaitWriteFinish:{stabilityThreshold:100,pollInterval:50}});let Q=()=>this.scheduleRefresh();this.gitWatcher.on("change",(q)=>{if(q===X)this.ignorers=this.loadGitignores();Q()}),this.gitWatcher.on("add",Q),this.gitWatcher.on("unlink",Q),this.gitWatcher.on("error",(q)=>{let z=q instanceof Error?q.message:String(q);this.emit("error",`Git watcher error: ${z}`)}),this.workingDirWatcher.on("change",Q),this.workingDirWatcher.on("add",Q),this.workingDirWatcher.on("unlink",Q),this.workingDirWatcher.on("error",(q)=>{let z=q instanceof Error?q.message:String(q);this.emit("error",`Working dir watcher error: ${z}`)})}dispose(){if(this.diffDebounceTimer)clearTimeout(this.diffDebounceTimer);this.gitWatcher?.close(),this.workingDirWatcher?.close(),E5(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 z8(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 z8(this.repoPath);if(!$.isRepo){this.updateState({status:$,diff:null,isLoading:!1,error:"Not a git repository"});return}let[J,K]=await Promise.all([u(this.repoPath,void 0,!1),u(this.repoPath,void 0,!0)]),Z={unstaged:T8(J.raw),staged:T8(K.raw)},{displayDiff:X,combinedFileDiffs:Q}=await this.resolveFileDiffs($,J);this.updateState({status:$,diff:X,combinedFileDiffs:Q,hunkCounts:Z,isLoading:!1})}catch($){this.updateState({isLoading:!1,error:$ instanceof Error?$.message:"Unknown error"})}}async resolveFileDiffs($,J){let K=this._state.selectedFile;if(!K)return{displayDiff:J,combinedFileDiffs:null};let Z=$.files.find((z)=>z.path===K.path&&z.staged===K.staged)??$.files.find((z)=>z.path===K.path);if(!Z)return this.updateState({selectedFile:null}),{displayDiff:J,combinedFileDiffs:null};if(Z.status==="untracked"){let z=await N8(this.repoPath,Z.path);return{displayDiff:z,combinedFileDiffs:{unstaged:z,staged:{raw:"",lines:[]}}}}let[X,Q]=await Promise.all([u(this.repoPath,Z.path,!1),u(this.repoPath,Z.path,!0)]);return{displayDiff:Z.staged?Q:X,combinedFileDiffs:{unstaged:X,staged:Q}}}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;await this.doFetchDiffForFile($)}).catch((J)=>{this.updateState({error:`Failed to load diff: ${J instanceof Error?J.message:String(J)}`})})}async doFetchDiffForFile($){if(!$){let Z=await k5(this.repoPath);if(this._state.selectedFile===null)this.updateState({diff:Z,combinedFileDiffs:null});return}if($.status==="untracked"){let Z=await N8(this.repoPath,$.path);if($===this._state.selectedFile)this.updateState({diff:Z,combinedFileDiffs:{unstaged:Z,staged:{raw:"",lines:[]}}});return}let[J,K]=await Promise.all([u(this.repoPath,$.path,!1),u(this.repoPath,$.path,!0)]);if($===this._state.selectedFile){let Z=$.staged?K:J;this.updateState({diff:Z,combinedFileDiffs:{unstaged:J,staged:K}})}}async stage($){try{await this.queue.enqueueMutation(()=>a0(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(()=>s0(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 stageHunk($){try{await this.queue.enqueueMutation(async()=>J5(this.repoPath,$)),this.scheduleRefresh()}catch(J){await this.refresh(),this.updateState({error:`Failed to stage hunk: ${J instanceof Error?J.message:String(J)}`})}}async unstageHunk($){try{await this.queue.enqueueMutation(async()=>K5(this.repoPath,$)),this.scheduleRefresh()}catch(J){await this.refresh(),this.updateState({error:`Failed to unstage hunk: ${J instanceof Error?J.message:String(J)}`})}}async discard($){if($.staged||$.status==="untracked")return;try{await this.queue.enqueueMutation(()=>t0(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(()=>n0(this.repoPath)),await this.refresh()}catch($){this.updateState({error:`Failed to stage all: ${$ instanceof Error?$.message:String($)}`})}}async unstageAll(){try{await this.queue.enqueueMutation(()=>i0(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(()=>e0(this.repoPath,$,J)),await this.refresh()}catch(K){this.updateState({error:`Failed to commit: ${K instanceof Error?K.message:String(K)}`})}}async push(){if(this._remoteState.inProgress)return;await this.runRemoteOperation("push",()=>Z5(this.repoPath))}async fetchRemote(){if(this._remoteState.inProgress)return;await this.runRemoteOperation("fetch",()=>X5(this.repoPath))}async pullRebase(){if(this._remoteState.inProgress)return;await this.runRemoteOperation("pull",()=>Q5(this.repoPath))}async runRemoteOperation($,J){this.updateRemoteState({operation:$,inProgress:!0,error:null,lastResult:null});try{let K=await this.queue.enqueue(J);this.updateRemoteState({inProgress:!1,lastResult:K}),this.scheduleRefresh()}catch(K){let Z=K instanceof Error?K.message:String(K);this.updateRemoteState({inProgress:!1,error:Z})}}async loadStashList(){try{let $=await this.queue.enqueue(()=>z5(this.repoPath));this.updateState({stashList:$})}catch{}}async stash($){if(this._remoteState.inProgress)return;await this.runRemoteOperation("stash",()=>V5(this.repoPath,$)),await this.loadStashList()}async stashPop($=0){if(this._remoteState.inProgress)return;await this.runRemoteOperation("stashPop",()=>Y5(this.repoPath,$)),await this.loadStashList()}async getLocalBranches(){return this.queue.enqueue(()=>U5(this.repoPath))}async switchBranch($){if(this._remoteState.inProgress)return;await this.runRemoteOperation("branchSwitch",()=>B5(this.repoPath,$)),this.updateCompareState({compareBaseBranch:null})}async createBranch($){if(this._remoteState.inProgress)return;await this.runRemoteOperation("branchCreate",()=>G5(this.repoPath,$)),this.updateCompareState({compareBaseBranch:null})}async softReset($=1){if(this._remoteState.inProgress)return;await this.runRemoteOperation("softReset",()=>j5(this.repoPath,$))}async cherryPick($){if(this._remoteState.inProgress)return;await this.runRemoteOperation("cherryPick",()=>_5(this.repoPath,$))}async revertCommit($){if(this._remoteState.inProgress)return;await this.runRemoteOperation("revert",()=>M5(this.repoPath,$))}clearRemoteState(){this.updateRemoteState({operation:null,error:null,lastResult:null})}async getHeadCommitMessage(){return this.queue.enqueue(()=>$5(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=y5(this.repoPath)??await R5(this.repoPath),this.updateCompareState({compareBaseBranch:J});if(J){let K=$?await L5(this.repoPath,J):await E8(this.repoPath,J);this.updateCompareState({compareDiff:K,compareLoading:!1})}else this.updateCompareState({compareDiff:null,compareLoading:!1,compareError:"No base branch found"})}async getCandidateBaseBranches(){return H8(this.repoPath)}async setCompareBaseBranch($,J=!1){this.updateCompareState({compareBaseBranch:$}),C5(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 q5(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 k8(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 k8(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 x$=new Map;function w5($){let J=x$.get($);if(!J)J=new b5($),x$.set($,J);return J}function R8($){let J=x$.get($);if(J)J.dispose(),x$.delete($)}class L8{screen;layout;uiState;gitManager=null;followMode=null;explorerManager=null;config;commandServer;repoPath;currentTheme;commitFlowState;commitTextarea=null;activeModal=null;remoteClearTimer=null;bottomPaneTotalRows=0;bottomPaneHunkCount=0;bottomPaneHunkBoundaries=[];pendingSelectionAnchor=null;cachedFlatFiles=[];pendingFlatSelectionPath=null;pendingHunkIndex=null;combinedHunkMapping=[];constructor($){this.config=$.config,this.commandServer=$.commandServer??null,this.repoPath=$.initialPath??process.cwd(),this.currentTheme=$.config.theme,this.uiState=new W8({splitRatio:$.config.splitRatio??0.4}),this.screen=x5.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 g$(this.screen,this.uiState.state.splitRatio),this.screen.on("resize",()=>{setImmediate(()=>this.render())}),this.commitFlowState=new v8({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=x5.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 I$(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(){x8(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(),toggleCurrentHunk:()=>this.toggleCurrentHunk(),navigateNextHunk:()=>this.navigateNextHunk(),navigatePrevHunk:()=>this.navigatePrevHunk(),push:()=>this.gitManager?.push(),fetchRemote:()=>this.gitManager?.fetchRemote(),pullRebase:()=>this.gitManager?.pullRebase(),stash:()=>this.gitManager?.stash(),stashPop:()=>this.gitManager?.stashPop(),openStashListModal:()=>this.openStashListModal(),openBranchPicker:()=>this.openBranchPicker(),showSoftResetConfirm:()=>this.showSoftResetConfirm(),cherryPickSelected:()=>this.cherryPickSelected(),revertSelected:()=>this.revertSelected()},{hasActiveModal:()=>this.activeModal!==null,getBottomTab:()=>this.uiState.state.bottomTab,getCurrentPane:()=>this.uiState.state.currentPane,isCommitInputFocused:()=>this.commitFlowState.state.inputFocused,isRemoteInProgress:()=>this.gitManager?.remoteState.inProgress??!1,getStatusFiles:()=>this.gitManager?.state.status?.files??[],getSelectedIndex:()=>this.uiState.state.selectedIndex,uiState:this.uiState,getExplorerManager:()=>this.explorerManager,commitFlowState:this.commitFlowState,getGitManager:()=>this.gitManager,layout:this.layout,getCachedFlatFiles:()=>this.cachedFlatFiles})}setupMouseEventHandlers(){b0(this.layout,{selectHistoryCommitByIndex:($)=>this.selectHistoryCommitByIndex($),selectCompareItem:($)=>this.selectCompareItem($),selectFileByIndex:($)=>this.selectFileByIndex($),toggleFileByIndex:($)=>this.toggleFileByIndex($),enterExplorerDirectory:()=>this.enterExplorerDirectory(),toggleMouseMode:()=>this.toggleMouseMode(),toggleFollow:()=>this.toggleFollow(),selectHunkAtRow:($)=>this.selectHunkAtRow($),focusCommitInput:()=>this.focusCommitInput(),toggleAmend:()=>{this.commitFlowState.toggleAmend(),this.render()},render:()=>this.render()},{uiState:this.uiState,getExplorerManager:()=>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,getCachedFlatFiles:()=>this.cachedFlatFiles})}async toggleFlatEntry($){if(this.pendingFlatSelectionPath=$.path,$.stagingState==="staged"){if($.stagedEntry)await this.gitManager?.unstage($.stagedEntry)}else if($.unstagedEntry)await this.gitManager?.stage($.unstagedEntry)}async toggleFileByIndex($){if(this.uiState.state.flatViewMode){let J=w(this.cachedFlatFiles,$);if(J)await this.toggleFlatEntry(J)}else{let J=this.gitManager?.state.status?.files??[],K=b(J,$);if(K)if(this.pendingSelectionAnchor=a(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!=="diff")this.uiState.setSelectedHunkIndex(0);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("")}else if(J==="commit"){if(this.gitManager?.loadStashList(),!this.gitManager?.historyState.commits.length)this.gitManager?.loadHistory()}}),this.uiState.on("modal-change",(J)=>{if(this.activeModal)this.activeModal=null;if(J==="theme")this.activeModal=new Y8(this.screen,this.currentTheme,(K)=>{this.currentTheme=K,Z8({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 U8(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 B8(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)Z8({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(),R8($??this.repoPath);this.gitManager=w5(this.repoPath),this.gitManager.on("state-change",()=>{if(!this.gitManager?.state.isLoading)this.reconcileSelectionAfterStateChange();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.on("remote-state-change",(J)=>{if(this.remoteClearTimer)clearTimeout(this.remoteClearTimer);if(J.lastResult&&!J.inProgress)this.remoteClearTimer=setTimeout(()=>{this.gitManager?.clearRemoteState()},3000);else if(J.error)this.remoteClearTimer=setTimeout(()=>{this.gitManager?.clearRemoteState()},5000);this.render()}),this.gitManager.startWatching(),this.gitManager.refresh(),this.initExplorerManager()}reconcileSelectionAfterStateChange(){let $=this.gitManager?.state.status?.files??[];if(this.uiState.state.flatViewMode&&this.pendingFlatSelectionPath){let J=_$($,this.gitManager?.state.hunkCounts??null),K=this.pendingFlatSelectionPath;this.pendingFlatSelectionPath=null;let Z=w8(J,K);if(Z>=0)this.uiState.setSelectedIndex(Z),this.selectFileByIndex(Z);else if(J.length>0){let X=Math.min(this.uiState.state.selectedIndex,J.length-1);this.uiState.setSelectedIndex(X),this.selectFileByIndex(X)}return}if(this.pendingSelectionAnchor){let J=this.pendingSelectionAnchor;this.pendingSelectionAnchor=null;let K=y8($,J.category,J.categoryIndex);this.uiState.setSelectedIndex(K),this.selectFileByIndex(K);return}if(this.uiState.state.flatViewMode){let K=_$($,this.gitManager?.state.hunkCounts??null).length-1;if(K>=0&&this.uiState.state.selectedIndex>K)this.uiState.setSelectedIndex(K)}else if($.length>0){let J=$.length-1;if(this.uiState.state.selectedIndex>J)this.uiState.setSelectedIndex(J)}}initExplorerManager(){if(this.explorerManager)this.explorerManager.dispose();let $={hideHidden:!0,hideGitignored:!0,showOnlyChanges:!1};this.explorerManager=new V8(this.repoPath,$),this.explorerManager.on("state-change",()=>{this.render()}),this.explorerManager.loadDirectory(""),this.explorerManager.loadFilePaths(),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}}scrollActiveDiffPane($){let J=this.uiState.state;if(J.bottomTab==="explorer"){let K=Math.max(0,J.explorerFileScrollOffset+$);this.uiState.setExplorerFileScrollOffset(K)}else{let K=Math.max(0,J.diffScrollOffset+$);this.uiState.setDiffScrollOffset(K)}}navigateFileList($){let J=this.uiState.state,K=this.gitManager?.state.status?.files??[],Z=J.flatViewMode?this.cachedFlatFiles.length-1:K.length-1;if(Z<0)return;let X=$===-1?Math.max(0,J.selectedIndex-1):Math.min(Z,J.selectedIndex+1);this.uiState.setSelectedIndex(X),this.selectFileByIndex(X);let Q=J.flatViewMode?X+1:b8(X,K);this.scrollToKeepRowVisible(Q,$,J.fileListScrollOffset)}scrollToKeepRowVisible($,J,K){if(J===-1&&$<K)this.uiState.setFileListScrollOffset($);else if(J===1){let Z=K+this.layout.dimensions.topPaneHeight-1;if($>=Z)this.uiState.setFileListScrollOffset(K+($-Z+1))}}navigateActiveList($){let J=this.uiState.state.bottomTab;if(J==="history")if($===-1)this.navigateHistoryUp();else this.navigateHistoryDown();else if(J==="compare")if($===-1)this.navigateCompareUp();else this.navigateCompareDown();else if(J==="explorer")if($===-1)this.navigateExplorerUp();else this.navigateExplorerDown();else this.navigateFileList($)}navigateUp(){if(this.uiState.state.currentPane!=="diff")this.navigateActiveList(-1);else this.scrollActiveDiffPane(-3)}navigateDown(){if(this.uiState.state.currentPane!=="diff")this.navigateActiveList(1);else this.scrollActiveDiffPane(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=f8(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=o$(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=v$(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=o$(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=v$(Z,J,K),q=X.compareScrollOffset+this.layout.dimensions.topPaneHeight-1;if(Q>=q)this.uiState.setCompareScrollOffset(X.compareScrollOffset+(Q-q+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($){if(this.uiState.state.flatViewMode){let J=w(this.cachedFlatFiles,$);if(J){let K=J.unstagedEntry??J.stagedEntry;if(K)this.uiState.setDiffScrollOffset(0),this.uiState.setSelectedHunkIndex(0),this.gitManager?.selectFile(K)}}else{let J=this.gitManager?.state.status?.files??[],K=b(J,$);if(K)this.uiState.setDiffScrollOffset(0),this.uiState.setSelectedHunkIndex(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;if(this.uiState.state.flatViewMode){let K=w(this.cachedFlatFiles,J);if(!K)return;let Z=K.unstagedEntry;if(Z)this.pendingFlatSelectionPath=K.path,await this.gitManager?.stage(Z)}else{let K=b($,J);if(K&&!K.staged)this.pendingSelectionAnchor=a($,J),await this.gitManager?.stage(K)}}async unstageSelected(){let $=this.gitManager?.state.status?.files??[],J=this.uiState.state.selectedIndex;if(this.uiState.state.flatViewMode){let K=w(this.cachedFlatFiles,J);if(!K)return;let Z=K.stagedEntry;if(Z)this.pendingFlatSelectionPath=K.path,await this.gitManager?.unstage(Z)}else{let K=b($,J);if(K?.staged)this.pendingSelectionAnchor=a($,J),await this.gitManager?.unstage(K)}}async toggleSelected(){let $=this.uiState.state.selectedIndex;if(this.uiState.state.flatViewMode){let J=w(this.cachedFlatFiles,$);if(J)await this.toggleFlatEntry(J)}else{let J=this.gitManager?.state.status?.files??[],K=b(J,$);if(K)if(this.pendingSelectionAnchor=a(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 G8(this.screen,$.path,async()=>{this.activeModal=null,await this.gitManager?.discard($)},()=>{this.activeModal=null}),this.activeModal.focus()}navigateNextHunk(){let $=this.uiState.state.selectedHunkIndex;if(this.bottomPaneHunkCount>0&&$<this.bottomPaneHunkCount-1)this.uiState.setSelectedHunkIndex($+1),this.scrollHunkIntoView($+1)}navigatePrevHunk(){let $=this.uiState.state.selectedHunkIndex;if($>0)this.uiState.setSelectedHunkIndex($-1),this.scrollHunkIntoView($-1)}scrollHunkIntoView($){let J=this.bottomPaneHunkBoundaries[$];if(!J)return;let K=this.uiState.state.diffScrollOffset,Z=this.layout.dimensions.bottomPaneHeight;if(J.startRow<K||J.startRow>=K+Z)this.uiState.setDiffScrollOffset(J.startRow)}selectHunkAtRow($){if(this.uiState.state.bottomTab!=="diff")return;if(this.bottomPaneHunkBoundaries.length===0)return;this.uiState.setPane("diff");let J=this.uiState.state.diffScrollOffset+$;for(let K=0;K<this.bottomPaneHunkBoundaries.length;K++){let Z=this.bottomPaneHunkBoundaries[K];if(J>=Z.startRow&&J<Z.endRow){this.uiState.setSelectedHunkIndex(K);return}}}async toggleCurrentHunk(){let $=this.gitManager?.state.selectedFile;if(!$||$.status==="untracked")return;if(this.uiState.state.flatViewMode)await this.toggleCurrentHunkFlat();else await this.toggleCurrentHunkCategorized($)}async toggleCurrentHunkFlat(){let $=this.combinedHunkMapping[this.uiState.state.selectedHunkIndex];if(!$)return;let J=this.gitManager?.state.combinedFileDiffs;if(!J)return;let K=$.source==="unstaged"?J.unstaged.raw:J.staged.raw,Z=A8(K,$.hunkIndex);if(!Z)return;if(this.pendingHunkIndex=this.uiState.state.selectedHunkIndex,$.source==="staged")await this.gitManager?.unstageHunk(Z);else await this.gitManager?.stageHunk(Z)}async toggleCurrentHunkCategorized($){let J=this.gitManager?.state.diff?.raw;if(!J)return;let K=A8(J,this.uiState.state.selectedHunkIndex);if(!K)return;let Z=this.gitManager?.state.status?.files??[];if(this.pendingSelectionAnchor=a(Z,this.uiState.state.selectedIndex),$.staged)await this.gitManager?.unstageHunk(K);else await this.gitManager?.stageHunk(K)}async openFileFinder(){let $=this.explorerManager?.getCachedFilePaths()??[];if($.length===0)await this.explorerManager?.loadFilePaths(),$=this.explorerManager?.getCachedFilePaths()??[];if($.length===0)return;this.activeModal=new j8(this.screen,$,async(J)=>{if(this.activeModal=null,this.uiState.state.bottomTab!=="explorer")this.uiState.setTab("explorer");if(await this.explorerManager?.navigateToPath(J)){let Z=this.explorerManager?.state.selectedIndex??0;this.uiState.setExplorerSelectedIndex(Z),this.uiState.setExplorerFileScrollOffset(0);let X=this.layout.dimensions.topPaneHeight;if(Z>=X)this.uiState.setExplorerScrollOffset(Z-Math.floor(X/2));else this.uiState.setExplorerScrollOffset(0)}this.render()},()=>{this.activeModal=null,this.render()}),this.activeModal.focus()}openStashListModal(){let $=this.gitManager?.state.stashList??[];this.activeModal=new _8(this.screen,$,(J)=>{this.activeModal=null,this.gitManager?.stashPop(J)},()=>{this.activeModal=null}),this.activeModal.focus()}openBranchPicker(){this.gitManager?.getLocalBranches().then(($)=>{this.activeModal=new M8(this.screen,$,(J)=>{this.activeModal=null,this.gitManager?.switchBranch(J)},(J)=>{this.activeModal=null,this.gitManager?.createBranch(J)},()=>{this.activeModal=null}),this.activeModal.focus()})}showSoftResetConfirm(){let $=this.gitManager?.historyState.commits[0];if(!$)return;this.activeModal=new O8(this.screen,$,()=>{this.activeModal=null,this.gitManager?.softReset()},()=>{this.activeModal=null}),this.activeModal.focus()}cherryPickSelected(){let $=this.gitManager?.historyState.selectedCommit;if(!$)return;this.activeModal=new S$(this.screen,"Cherry-pick",$,()=>{this.activeModal=null,this.gitManager?.cherryPick($.hash)},()=>{this.activeModal=null}),this.activeModal.focus()}revertSelected(){let $=this.gitManager?.historyState.selectedCommit;if(!$)return;this.activeModal=new S$(this.screen,"Revert",$,()=>{this.activeModal=null,this.gitManager?.revertCommit($.hash)},()=>{this.activeModal=null}),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 I$(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(){if(this.updateHeader(),this.updateTopPane(),this.updateBottomPane(),this.pendingHunkIndex!==null&&this.bottomPaneHunkCount>0){let $=Math.min(this.pendingHunkIndex,this.bottomPaneHunkCount-1);this.pendingHunkIndex=null,this.uiState.setSelectedHunkIndex($),this.updateBottomPane()}this.updateFooter(),this.screen.render()}updateHeader(){let $=this.gitManager?.state,J=this.screen.width||80,K=m0(this.repoPath,$?.status?.branch??null,$?.isLoading??!1,$?.error??null,J,this.gitManager?.remoteState??null);this.layout.headerBox.setContent(K)}updateTopPane(){let $=this.uiState.state,J=this.screen.width||80,K=this.gitManager?.state.status?.files??[];if($.flatViewMode)this.cachedFlatFiles=_$(K,this.gitManager?.state.hunkCounts??null);let Z=y0($,K,this.gitManager?.historyState?.commits??[],this.gitManager?.compareState?.compareDiff??null,this.compareSelection,this.explorerManager?.state,J,this.layout.dimensions.topPaneHeight,this.gitManager?.state.hunkCounts,$.flatViewMode?this.cachedFlatFiles:void 0);this.layout.topPane.setContent(Z)}updateBottomPane(){let $=this.uiState.state,J=this.screen.width||80,Z=(this.gitManager?.state.status?.files??[]).filter((B)=>B.staged).length;this.commitFlowState.setStagedCount(Z);let X=$.bottomTab==="diff"&&$.currentPane==="diff",Q=X?$.selectedHunkIndex:void 0,q=X?this.gitManager?.state.selectedFile?.staged:void 0,{content:z,totalRows:V,hunkCount:Y,hunkBoundaries:U,hunkMapping:j}=C0($,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,Q,q,$.flatViewMode?this.gitManager?.state.combinedFileDiffs:void 0,this.gitManager?.state.status?.branch??null,this.gitManager?.remoteState??null,this.gitManager?.state.stashList,this.gitManager?.historyState.commits[0]??null);if(this.bottomPaneTotalRows=V,this.bottomPaneHunkCount=Y,this.bottomPaneHunkBoundaries=U,this.combinedHunkMapping=j??[],this.uiState.clampSelectedHunkIndex(Y),this.layout.bottomPane.setContent(z),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=h0($.bottomTab,$.mouseEnabled,$.autoTabEnabled,$.wrapMode,this.followMode?.isEnabled??!1,this.explorerManager?.showOnlyChanges??!1,J,$.currentPane);this.layout.footerBox.setContent(K)}exit(){if(this.gitManager)R8(this.repoPath);if(this.explorerManager)this.explorerManager.dispose();if(this.followMode)this.followMode.stop();if(this.commandServer)this.commandServer.stop();if(this.remoteClearTimer)clearTimeout(this.remoteClearTimer);this.screen.destroy()}start(){return new Promise(($)=>{this.screen.on("destroy",()=>{$()})})}}import*as p5 from"net";import*as f from"fs";import{EventEmitter as U3}from"events";class F8 extends U3{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(f.existsSync(this.socketPath))f.unlinkSync(this.socketPath);return new Promise(($,J)=>{this.server=p5.createServer((K)=>{this.handleConnection(K)}),this.server.on("error",(K)=>{J(K)}),this.server.listen(this.socketPath,()=>{f.chmodSync(this.socketPath,384),$()})})}stop(){if(this.server)this.server.close(),this.server=null;if(f.existsSync(this.socketPath))f.unlinkSync(this.socketPath)}handleConnection($){let J="";$.on("data",async(K)=>{J+=K.toString();let Z=J.split(`
|
|
67
|
+
`);J=Z.pop()||"";for(let X of Z)if(X.trim()){let Q=await this.processCommand(X);$.write(JSON.stringify(Q)+`
|
|
68
|
+
`)}}),$.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 r(){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")}r();process.on("exit",r);process.on("SIGINT",()=>{r(),process.exit(0)});process.on("SIGTERM",()=>{r(),process.exit(0)});process.on("uncaughtException",($)=>{r(),console.error("Uncaught exception:",$),process.exit(1)});process.on("unhandledRejection",($)=>{r(),console.error("Unhandled rejection:",$),process.exit(1)});function B3($){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(`
|
|
64
69
|
diffstalker - Terminal git diff/status viewer
|
|
65
70
|
|
|
66
71
|
Usage: diffstalker [options] [path]
|
|
@@ -101,4 +106,4 @@ Keyboard:
|
|
|
101
106
|
Mouse:
|
|
102
107
|
Click Select file / focus pane
|
|
103
108
|
Scroll Navigate files / scroll diff
|
|
104
|
-
`),process.exit(0);else if(!
|
|
109
|
+
`),process.exit(0);else if(!Z.startsWith("-"))J.initialPath=Z}return J}async function G3(){let $=B3(process.argv.slice(2)),J=w0();if($.follow){if(J.watcherEnabled=!0,$.followFile)J.targetFile=$.followFile}if($.debug)J.debug=!0;let K=null;if($.socket){K=new F8($.socket);try{await K.start()}catch(X){console.error("Failed to start command server:",X),process.exit(1)}}if(await new L8({config:J,initialPath:$.initialPath,commandServer:K}).start(),K)K.stop();process.exit(0)}G3().catch(($)=>{console.error("Fatal error:",$),r(),process.exit(1)});
|