git-viewer 14.0.0 → 15.0.0
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/entry.bundled.js +758 -72
- package/dist/server.js +200 -1
- package/package.json +1 -1
package/dist/entry.bundled.js
CHANGED
|
@@ -1607,6 +1607,45 @@ async function fetchDiff(sha, signal) {
|
|
|
1607
1607
|
let res = await fetch(`/api/diff/${sha}`, { signal });
|
|
1608
1608
|
return res.json();
|
|
1609
1609
|
}
|
|
1610
|
+
async function fetchStatus(signal) {
|
|
1611
|
+
let res = await fetch("/api/status", { signal });
|
|
1612
|
+
return res.json();
|
|
1613
|
+
}
|
|
1614
|
+
async function stageFiles(paths) {
|
|
1615
|
+
await fetch("/api/stage", {
|
|
1616
|
+
method: "POST",
|
|
1617
|
+
headers: { "Content-Type": "application/json" },
|
|
1618
|
+
body: JSON.stringify({ paths })
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
async function unstageFiles(paths) {
|
|
1622
|
+
await fetch("/api/unstage", {
|
|
1623
|
+
method: "POST",
|
|
1624
|
+
headers: { "Content-Type": "application/json" },
|
|
1625
|
+
body: JSON.stringify({ paths })
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1628
|
+
async function commitChanges(message, amend) {
|
|
1629
|
+
await fetch("/api/commit", {
|
|
1630
|
+
method: "POST",
|
|
1631
|
+
headers: { "Content-Type": "application/json" },
|
|
1632
|
+
body: JSON.stringify({ message, amend })
|
|
1633
|
+
});
|
|
1634
|
+
}
|
|
1635
|
+
async function fetchLastCommit(signal) {
|
|
1636
|
+
let res = await fetch("/api/last-commit", { signal });
|
|
1637
|
+
return res.json();
|
|
1638
|
+
}
|
|
1639
|
+
async function fetchWorkingDiff(path, signal) {
|
|
1640
|
+
let params = new URLSearchParams({ path });
|
|
1641
|
+
let res = await fetch(`/api/working-diff?${params}`, { signal });
|
|
1642
|
+
return res.json();
|
|
1643
|
+
}
|
|
1644
|
+
async function fetchStagedDiff(path, signal) {
|
|
1645
|
+
let params = new URLSearchParams({ path });
|
|
1646
|
+
let res = await fetch(`/api/staged-diff?${params}`, { signal });
|
|
1647
|
+
return res.json();
|
|
1648
|
+
}
|
|
1610
1649
|
var AppStore = class extends TypedEventTarget {
|
|
1611
1650
|
constructor() {
|
|
1612
1651
|
super(...arguments);
|
|
@@ -1615,6 +1654,8 @@ var AppStore = class extends TypedEventTarget {
|
|
|
1615
1654
|
__publicField(this, "search", "");
|
|
1616
1655
|
__publicField(this, "selectedCommit", null);
|
|
1617
1656
|
__publicField(this, "fullscreenDiff", false);
|
|
1657
|
+
__publicField(this, "view", "commits");
|
|
1658
|
+
__publicField(this, "status", null);
|
|
1618
1659
|
}
|
|
1619
1660
|
setRefs(refs) {
|
|
1620
1661
|
this.refs = refs;
|
|
@@ -1638,6 +1679,14 @@ var AppStore = class extends TypedEventTarget {
|
|
|
1638
1679
|
this.dispatchEvent(new Event("fullscreenDiff"));
|
|
1639
1680
|
});
|
|
1640
1681
|
}
|
|
1682
|
+
setView(view) {
|
|
1683
|
+
this.view = view;
|
|
1684
|
+
this.dispatchEvent(new Event("view"));
|
|
1685
|
+
}
|
|
1686
|
+
setStatus(status) {
|
|
1687
|
+
this.status = status;
|
|
1688
|
+
this.dispatchEvent(new Event("status"));
|
|
1689
|
+
}
|
|
1641
1690
|
};
|
|
1642
1691
|
var colors = {
|
|
1643
1692
|
bg: "#ffffff",
|
|
@@ -1697,47 +1746,104 @@ function App(handle) {
|
|
|
1697
1746
|
function Sidebar(handle) {
|
|
1698
1747
|
let store = handle.context.get(App);
|
|
1699
1748
|
handle.on(store, {
|
|
1700
|
-
refs: () => handle.update()
|
|
1749
|
+
refs: () => handle.update(),
|
|
1750
|
+
status: () => handle.update(),
|
|
1751
|
+
view: () => handle.update()
|
|
1701
1752
|
});
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
borderBottom: `1px solid ${colors.border}`
|
|
1722
|
-
},
|
|
1723
|
-
children: "Git Tree Viewer"
|
|
1724
|
-
}
|
|
1725
|
-
),
|
|
1726
|
-
/* @__PURE__ */ jsx("div", { css: { flex: 1, overflow: "auto", padding: "8px 0" }, children: store.refs && /* @__PURE__ */ jsx(Fragment, { children: [
|
|
1727
|
-
/* @__PURE__ */ jsx(RefSection, { title: "LOCAL", nodes: store.refs.local }),
|
|
1728
|
-
Object.entries(store.refs.remotes).map(([remote, nodes]) => /* @__PURE__ */ jsx(
|
|
1729
|
-
RefSection,
|
|
1753
|
+
handle.queueTask(async (signal) => {
|
|
1754
|
+
let status = await fetchStatus(signal);
|
|
1755
|
+
store.setStatus(status);
|
|
1756
|
+
});
|
|
1757
|
+
return () => {
|
|
1758
|
+
let totalChanges = store.status ? store.status.staged.length + store.status.unstaged.length : 0;
|
|
1759
|
+
let isStageView = store.view === "stage";
|
|
1760
|
+
return /* @__PURE__ */ jsx(
|
|
1761
|
+
"div",
|
|
1762
|
+
{
|
|
1763
|
+
css: {
|
|
1764
|
+
borderRight: `1px solid ${colors.border}`,
|
|
1765
|
+
display: "flex",
|
|
1766
|
+
flexDirection: "column",
|
|
1767
|
+
overflow: "hidden"
|
|
1768
|
+
},
|
|
1769
|
+
children: [
|
|
1770
|
+
/* @__PURE__ */ jsx(
|
|
1771
|
+
"div",
|
|
1730
1772
|
{
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1773
|
+
css: {
|
|
1774
|
+
padding: "12px",
|
|
1775
|
+
fontWeight: 600,
|
|
1776
|
+
textTransform: "uppercase",
|
|
1777
|
+
letterSpacing: "0.5px",
|
|
1778
|
+
color: colors.textMuted,
|
|
1779
|
+
borderBottom: `1px solid ${colors.border}`
|
|
1780
|
+
},
|
|
1781
|
+
children: "Git Tree Viewer"
|
|
1782
|
+
}
|
|
1783
|
+
),
|
|
1784
|
+
/* @__PURE__ */ jsx("div", { css: { flex: 1, overflow: "auto", padding: "8px 0" }, children: [
|
|
1785
|
+
/* @__PURE__ */ jsx(
|
|
1786
|
+
"div",
|
|
1787
|
+
{
|
|
1788
|
+
css: {
|
|
1789
|
+
padding: "6px 12px",
|
|
1790
|
+
marginBottom: "8px",
|
|
1791
|
+
borderRadius: "3px",
|
|
1792
|
+
marginRight: "8px",
|
|
1793
|
+
marginLeft: "8px",
|
|
1794
|
+
display: "flex",
|
|
1795
|
+
alignItems: "center",
|
|
1796
|
+
justifyContent: "space-between",
|
|
1797
|
+
background: isStageView ? colors.accentDim : "transparent",
|
|
1798
|
+
color: isStageView ? colors.accent : colors.text,
|
|
1799
|
+
fontWeight: 600,
|
|
1800
|
+
userSelect: "none",
|
|
1801
|
+
"&:hover": {
|
|
1802
|
+
background: isStageView ? colors.accentDim : colors.bgLighter
|
|
1803
|
+
}
|
|
1804
|
+
},
|
|
1805
|
+
on: {
|
|
1806
|
+
click: () => {
|
|
1807
|
+
store.setFilter("");
|
|
1808
|
+
store.setView("stage");
|
|
1809
|
+
}
|
|
1810
|
+
},
|
|
1811
|
+
children: [
|
|
1812
|
+
/* @__PURE__ */ jsx("span", { children: "stage" }),
|
|
1813
|
+
totalChanges > 0 && /* @__PURE__ */ jsx(
|
|
1814
|
+
"span",
|
|
1815
|
+
{
|
|
1816
|
+
css: {
|
|
1817
|
+
background: colors.accent,
|
|
1818
|
+
color: "#fff",
|
|
1819
|
+
fontSize: "10px",
|
|
1820
|
+
padding: "2px 6px",
|
|
1821
|
+
borderRadius: "10px",
|
|
1822
|
+
fontWeight: 600
|
|
1823
|
+
},
|
|
1824
|
+
children: totalChanges
|
|
1825
|
+
}
|
|
1826
|
+
)
|
|
1827
|
+
]
|
|
1828
|
+
}
|
|
1829
|
+
),
|
|
1830
|
+
store.refs && /* @__PURE__ */ jsx(Fragment, { children: [
|
|
1831
|
+
/* @__PURE__ */ jsx(RefSection, { title: "LOCAL", nodes: store.refs.local }),
|
|
1832
|
+
Object.entries(store.refs.remotes).map(([remote, nodes]) => /* @__PURE__ */ jsx(
|
|
1833
|
+
RefSection,
|
|
1834
|
+
{
|
|
1835
|
+
title: remote.toUpperCase(),
|
|
1836
|
+
nodes,
|
|
1837
|
+
initialExpanded: false
|
|
1838
|
+
},
|
|
1839
|
+
remote
|
|
1840
|
+
))
|
|
1841
|
+
] })
|
|
1842
|
+
] })
|
|
1843
|
+
]
|
|
1844
|
+
}
|
|
1845
|
+
);
|
|
1846
|
+
};
|
|
1741
1847
|
}
|
|
1742
1848
|
function RefSection(handle) {
|
|
1743
1849
|
let expanded = null;
|
|
@@ -1758,7 +1864,7 @@ function RefSection(handle) {
|
|
|
1758
1864
|
textTransform: "uppercase",
|
|
1759
1865
|
letterSpacing: "0.5px",
|
|
1760
1866
|
color: colors.textMuted,
|
|
1761
|
-
|
|
1867
|
+
userSelect: "none",
|
|
1762
1868
|
"&:hover": { color: colors.text }
|
|
1763
1869
|
},
|
|
1764
1870
|
on: {
|
|
@@ -1794,10 +1900,10 @@ function RefNodeItem(handle) {
|
|
|
1794
1900
|
css: {
|
|
1795
1901
|
padding: `3px 12px`,
|
|
1796
1902
|
paddingLeft: `${paddingLeft}px`,
|
|
1797
|
-
cursor: "pointer",
|
|
1798
1903
|
color: colors.textMuted,
|
|
1799
1904
|
fontSize: "12px",
|
|
1800
1905
|
whiteSpace: "nowrap",
|
|
1906
|
+
userSelect: "none",
|
|
1801
1907
|
"&:hover": { color: colors.text }
|
|
1802
1908
|
},
|
|
1803
1909
|
on: {
|
|
@@ -1824,18 +1930,23 @@ function RefNodeItem(handle) {
|
|
|
1824
1930
|
css: {
|
|
1825
1931
|
padding: `3px 12px`,
|
|
1826
1932
|
paddingLeft: `${paddingLeft}px`,
|
|
1827
|
-
cursor: "pointer",
|
|
1828
1933
|
borderRadius: "3px",
|
|
1829
1934
|
marginRight: "8px",
|
|
1830
1935
|
background: isSelected ? colors.accentDim : "transparent",
|
|
1831
1936
|
color: node.current ? colors.accent : colors.text,
|
|
1832
1937
|
fontWeight: node.current ? 600 : 400,
|
|
1833
1938
|
whiteSpace: "nowrap",
|
|
1939
|
+
userSelect: "none",
|
|
1834
1940
|
"&:hover": {
|
|
1835
1941
|
background: isSelected ? colors.accentDim : colors.bgLighter
|
|
1836
1942
|
}
|
|
1837
1943
|
},
|
|
1838
|
-
on: {
|
|
1944
|
+
on: {
|
|
1945
|
+
click: () => {
|
|
1946
|
+
store.setFilter(node.fullName);
|
|
1947
|
+
store.setView("commits");
|
|
1948
|
+
}
|
|
1949
|
+
},
|
|
1839
1950
|
children: [
|
|
1840
1951
|
node.current && /* @__PURE__ */ jsx("span", { css: { fontSize: "8px", marginRight: "4px" }, children: "\u25CF" }),
|
|
1841
1952
|
node.name
|
|
@@ -1844,44 +1955,63 @@ function RefNodeItem(handle) {
|
|
|
1844
1955
|
);
|
|
1845
1956
|
};
|
|
1846
1957
|
}
|
|
1847
|
-
function MainPanel() {
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1958
|
+
function MainPanel(handle) {
|
|
1959
|
+
let store = handle.context.get(App);
|
|
1960
|
+
handle.on(store, {
|
|
1961
|
+
view: () => handle.update()
|
|
1962
|
+
});
|
|
1963
|
+
return () => {
|
|
1964
|
+
if (store.view === "stage") {
|
|
1965
|
+
return /* @__PURE__ */ jsx(
|
|
1966
|
+
"div",
|
|
1967
|
+
{
|
|
1968
|
+
css: {
|
|
1969
|
+
flex: 1,
|
|
1970
|
+
display: "flex",
|
|
1971
|
+
flexDirection: "column",
|
|
1972
|
+
overflow: "hidden"
|
|
1973
|
+
},
|
|
1974
|
+
children: /* @__PURE__ */ jsx(StagePanel, {})
|
|
1975
|
+
}
|
|
1976
|
+
);
|
|
1861
1977
|
}
|
|
1862
|
-
|
|
1978
|
+
return /* @__PURE__ */ jsx(
|
|
1979
|
+
"div",
|
|
1980
|
+
{
|
|
1981
|
+
css: {
|
|
1982
|
+
flex: 1,
|
|
1983
|
+
display: "flex",
|
|
1984
|
+
flexDirection: "column",
|
|
1985
|
+
overflow: "hidden"
|
|
1986
|
+
},
|
|
1987
|
+
children: [
|
|
1988
|
+
/* @__PURE__ */ jsx(CommitList, {}),
|
|
1989
|
+
/* @__PURE__ */ jsx(DiffPanel, {})
|
|
1990
|
+
]
|
|
1991
|
+
}
|
|
1992
|
+
);
|
|
1993
|
+
};
|
|
1863
1994
|
}
|
|
1864
1995
|
function CommitList(handle) {
|
|
1865
1996
|
let store = handle.context.get(App);
|
|
1866
1997
|
let commits = [];
|
|
1867
1998
|
let loading = true;
|
|
1868
|
-
async function
|
|
1869
|
-
loading = true;
|
|
1870
|
-
handle.update();
|
|
1999
|
+
async function doLoadCommits(signal) {
|
|
1871
2000
|
let ref = store.filter === "all" ? "all" : store.filter === "local" ? store.refs?.currentBranch : store.filter;
|
|
1872
2001
|
let result = await fetchCommits(ref, store.search, signal);
|
|
1873
2002
|
commits = result.commits;
|
|
1874
2003
|
loading = false;
|
|
1875
2004
|
handle.update();
|
|
1876
2005
|
}
|
|
2006
|
+
function loadCommits() {
|
|
2007
|
+
loading = true;
|
|
2008
|
+
handle.update(doLoadCommits);
|
|
2009
|
+
}
|
|
1877
2010
|
handle.on(store, {
|
|
1878
|
-
refs
|
|
1879
|
-
|
|
1880
|
-
},
|
|
1881
|
-
filter(_, signal) {
|
|
1882
|
-
loadCommits(signal);
|
|
1883
|
-
}
|
|
2011
|
+
refs: loadCommits,
|
|
2012
|
+
filter: loadCommits
|
|
1884
2013
|
});
|
|
2014
|
+
handle.queueTask(doLoadCommits);
|
|
1885
2015
|
return () => /* @__PURE__ */ jsx(
|
|
1886
2016
|
"div",
|
|
1887
2017
|
{
|
|
@@ -2008,7 +2138,7 @@ function FilterButton(handle) {
|
|
|
2008
2138
|
background: isActive ? colors.accentDim : "transparent",
|
|
2009
2139
|
color: isActive ? colors.accent : colors.text,
|
|
2010
2140
|
fontSize: "12px",
|
|
2011
|
-
|
|
2141
|
+
userSelect: "none",
|
|
2012
2142
|
"&:hover": { borderColor: colors.accent }
|
|
2013
2143
|
},
|
|
2014
2144
|
on: { click: () => store.setFilter(filter) },
|
|
@@ -2035,8 +2165,8 @@ function CommitRow(handle) {
|
|
|
2035
2165
|
"tr",
|
|
2036
2166
|
{
|
|
2037
2167
|
css: {
|
|
2038
|
-
|
|
2039
|
-
|
|
2168
|
+
background: isSelected ? colors.accentDim : "transparent",
|
|
2169
|
+
userSelect: "none"
|
|
2040
2170
|
},
|
|
2041
2171
|
on: { click: () => store.selectCommit(commit) },
|
|
2042
2172
|
children: [
|
|
@@ -2271,7 +2401,6 @@ function DiffPanel(handle) {
|
|
|
2271
2401
|
background: colors.bg,
|
|
2272
2402
|
color: colors.text,
|
|
2273
2403
|
fontSize: "12px",
|
|
2274
|
-
cursor: "pointer",
|
|
2275
2404
|
whiteSpace: "nowrap",
|
|
2276
2405
|
"&:hover": {
|
|
2277
2406
|
background: colors.bgLighter,
|
|
@@ -2409,7 +2538,7 @@ function FileListItem() {
|
|
|
2409
2538
|
{
|
|
2410
2539
|
css: {
|
|
2411
2540
|
padding: "6px 12px",
|
|
2412
|
-
|
|
2541
|
+
userSelect: "none",
|
|
2413
2542
|
"&:hover": {
|
|
2414
2543
|
background: colors.bgLighter
|
|
2415
2544
|
}
|
|
@@ -2535,4 +2664,561 @@ function FileListItem() {
|
|
|
2535
2664
|
);
|
|
2536
2665
|
};
|
|
2537
2666
|
}
|
|
2667
|
+
function StagePanel(handle) {
|
|
2668
|
+
let store = handle.context.get(App);
|
|
2669
|
+
let selectedFile = null;
|
|
2670
|
+
let diffHtml = null;
|
|
2671
|
+
let commitMessage = "";
|
|
2672
|
+
let savedMessage = "";
|
|
2673
|
+
let amend = false;
|
|
2674
|
+
let lastCommit = null;
|
|
2675
|
+
let loading = false;
|
|
2676
|
+
async function loadStatus(signal) {
|
|
2677
|
+
let status = await fetchStatus(signal);
|
|
2678
|
+
store.setStatus(status);
|
|
2679
|
+
}
|
|
2680
|
+
async function loadDiff(path, type, signal) {
|
|
2681
|
+
try {
|
|
2682
|
+
let result = type === "unstaged" ? await fetchWorkingDiff(path, signal) : await fetchStagedDiff(path, signal);
|
|
2683
|
+
if (signal.aborted) return;
|
|
2684
|
+
diffHtml = result.diffHtml;
|
|
2685
|
+
} catch {
|
|
2686
|
+
if (signal.aborted) return;
|
|
2687
|
+
diffHtml = "";
|
|
2688
|
+
}
|
|
2689
|
+
handle.update();
|
|
2690
|
+
}
|
|
2691
|
+
async function handleStage(paths) {
|
|
2692
|
+
loading = true;
|
|
2693
|
+
handle.update();
|
|
2694
|
+
await stageFiles(paths);
|
|
2695
|
+
let status = await fetchStatus();
|
|
2696
|
+
store.setStatus(status);
|
|
2697
|
+
if (selectedFile && selectedFile.type === "unstaged" && paths.includes(selectedFile.path)) {
|
|
2698
|
+
selectedFile = { path: selectedFile.path, type: "staged" };
|
|
2699
|
+
}
|
|
2700
|
+
loading = false;
|
|
2701
|
+
handle.update();
|
|
2702
|
+
}
|
|
2703
|
+
async function handleUnstage(paths) {
|
|
2704
|
+
loading = true;
|
|
2705
|
+
handle.update();
|
|
2706
|
+
await unstageFiles(paths);
|
|
2707
|
+
let status = await fetchStatus();
|
|
2708
|
+
store.setStatus(status);
|
|
2709
|
+
if (selectedFile && selectedFile.type === "staged" && paths.includes(selectedFile.path)) {
|
|
2710
|
+
selectedFile = { path: selectedFile.path, type: "unstaged" };
|
|
2711
|
+
}
|
|
2712
|
+
loading = false;
|
|
2713
|
+
handle.update();
|
|
2714
|
+
}
|
|
2715
|
+
async function handleCommit() {
|
|
2716
|
+
if (!commitMessage.trim()) return;
|
|
2717
|
+
loading = true;
|
|
2718
|
+
handle.update();
|
|
2719
|
+
await commitChanges(commitMessage, amend);
|
|
2720
|
+
commitMessage = "";
|
|
2721
|
+
amend = false;
|
|
2722
|
+
lastCommit = null;
|
|
2723
|
+
let status = await fetchStatus();
|
|
2724
|
+
store.setStatus(status);
|
|
2725
|
+
selectedFile = null;
|
|
2726
|
+
diffHtml = null;
|
|
2727
|
+
loading = false;
|
|
2728
|
+
handle.update();
|
|
2729
|
+
}
|
|
2730
|
+
async function toggleAmend(checked) {
|
|
2731
|
+
amend = checked;
|
|
2732
|
+
if (checked) {
|
|
2733
|
+
savedMessage = commitMessage;
|
|
2734
|
+
lastCommit = await fetchLastCommit();
|
|
2735
|
+
commitMessage = lastCommit.subject + (lastCommit.body ? "\n\n" + lastCommit.body : "");
|
|
2736
|
+
} else {
|
|
2737
|
+
commitMessage = savedMessage;
|
|
2738
|
+
lastCommit = null;
|
|
2739
|
+
}
|
|
2740
|
+
handle.update();
|
|
2741
|
+
}
|
|
2742
|
+
handle.on(store, {
|
|
2743
|
+
status: () => handle.update()
|
|
2744
|
+
});
|
|
2745
|
+
handle.queueTask(loadStatus);
|
|
2746
|
+
async function selectFile(path, type, signal) {
|
|
2747
|
+
if (selectedFile?.path === path && selectedFile?.type === type) {
|
|
2748
|
+
return;
|
|
2749
|
+
}
|
|
2750
|
+
selectedFile = { path, type };
|
|
2751
|
+
handle.update();
|
|
2752
|
+
await loadDiff(path, type, signal);
|
|
2753
|
+
}
|
|
2754
|
+
return () => {
|
|
2755
|
+
let staged = store.status?.staged ?? [];
|
|
2756
|
+
let unstaged = store.status?.unstaged ?? [];
|
|
2757
|
+
let displayStaged = staged;
|
|
2758
|
+
if (amend && lastCommit) {
|
|
2759
|
+
let stagedPaths = new Set(staged.map((f) => f.path));
|
|
2760
|
+
let amendFiles = lastCommit.files.filter((f) => !stagedPaths.has(f.path));
|
|
2761
|
+
displayStaged = [...staged, ...amendFiles];
|
|
2762
|
+
}
|
|
2763
|
+
return /* @__PURE__ */ jsx(
|
|
2764
|
+
"div",
|
|
2765
|
+
{
|
|
2766
|
+
css: {
|
|
2767
|
+
flex: 1,
|
|
2768
|
+
display: "flex",
|
|
2769
|
+
flexDirection: "column",
|
|
2770
|
+
overflow: "hidden"
|
|
2771
|
+
},
|
|
2772
|
+
children: [
|
|
2773
|
+
/* @__PURE__ */ jsx(
|
|
2774
|
+
"div",
|
|
2775
|
+
{
|
|
2776
|
+
css: {
|
|
2777
|
+
flex: "1 1 60%",
|
|
2778
|
+
display: "flex",
|
|
2779
|
+
flexDirection: "column",
|
|
2780
|
+
borderBottom: `1px solid ${colors.border}`,
|
|
2781
|
+
overflow: "hidden"
|
|
2782
|
+
},
|
|
2783
|
+
children: [
|
|
2784
|
+
/* @__PURE__ */ jsx(
|
|
2785
|
+
"div",
|
|
2786
|
+
{
|
|
2787
|
+
css: {
|
|
2788
|
+
padding: "8px 12px",
|
|
2789
|
+
borderBottom: `1px solid ${colors.border}`,
|
|
2790
|
+
background: colors.bgLight,
|
|
2791
|
+
fontSize: "12px",
|
|
2792
|
+
fontWeight: 600
|
|
2793
|
+
},
|
|
2794
|
+
children: selectedFile ? `${selectedFile.type === "unstaged" ? "Unstaged" : "Staged"} changes for ${selectedFile.path}` : "Select a file to view changes"
|
|
2795
|
+
}
|
|
2796
|
+
),
|
|
2797
|
+
/* @__PURE__ */ jsx("div", { css: { flex: 1, overflow: "auto", background: colors.bg }, children: diffHtml ? /* @__PURE__ */ jsx(
|
|
2798
|
+
"section",
|
|
2799
|
+
{
|
|
2800
|
+
css: {
|
|
2801
|
+
"& .d2h-wrapper": { background: "transparent" },
|
|
2802
|
+
"& .d2h-file-header": {
|
|
2803
|
+
background: colors.bgLighter,
|
|
2804
|
+
borderBottom: `1px solid ${colors.border}`,
|
|
2805
|
+
padding: "8px 12px",
|
|
2806
|
+
position: "sticky",
|
|
2807
|
+
top: 0,
|
|
2808
|
+
zIndex: 1
|
|
2809
|
+
},
|
|
2810
|
+
"& .d2h-file-name": { color: colors.text },
|
|
2811
|
+
"& .d2h-code-line": { padding: "0 8px" },
|
|
2812
|
+
"& .d2h-code-line-ctn": { color: colors.text },
|
|
2813
|
+
"& .d2h-ins": { background: "#dafbe1" },
|
|
2814
|
+
"& .d2h-del": { background: "#ffebe9" },
|
|
2815
|
+
"& .d2h-ins .d2h-code-line-ctn": { color: colors.green },
|
|
2816
|
+
"& .d2h-del .d2h-code-line-ctn": { color: colors.red },
|
|
2817
|
+
"& .d2h-code-linenumber": {
|
|
2818
|
+
color: colors.textMuted,
|
|
2819
|
+
borderRight: `1px solid ${colors.border}`
|
|
2820
|
+
},
|
|
2821
|
+
"& .d2h-file-diff": {
|
|
2822
|
+
borderBottom: `1px solid ${colors.border}`
|
|
2823
|
+
},
|
|
2824
|
+
"& .d2h-diff-tbody": { position: "relative" }
|
|
2825
|
+
},
|
|
2826
|
+
innerHTML: diffHtml
|
|
2827
|
+
}
|
|
2828
|
+
) : selectedFile ? /* @__PURE__ */ jsx(
|
|
2829
|
+
"div",
|
|
2830
|
+
{
|
|
2831
|
+
css: {
|
|
2832
|
+
padding: "20px",
|
|
2833
|
+
textAlign: "center",
|
|
2834
|
+
color: colors.textMuted
|
|
2835
|
+
},
|
|
2836
|
+
children: "Loading diff..."
|
|
2837
|
+
}
|
|
2838
|
+
) : /* @__PURE__ */ jsx(
|
|
2839
|
+
"div",
|
|
2840
|
+
{
|
|
2841
|
+
css: {
|
|
2842
|
+
padding: "20px",
|
|
2843
|
+
textAlign: "center",
|
|
2844
|
+
color: colors.textMuted
|
|
2845
|
+
},
|
|
2846
|
+
children: "Select a file to view its diff"
|
|
2847
|
+
}
|
|
2848
|
+
) })
|
|
2849
|
+
]
|
|
2850
|
+
}
|
|
2851
|
+
),
|
|
2852
|
+
/* @__PURE__ */ jsx(
|
|
2853
|
+
"div",
|
|
2854
|
+
{
|
|
2855
|
+
css: {
|
|
2856
|
+
flex: "0 0 300px",
|
|
2857
|
+
display: "flex",
|
|
2858
|
+
gap: "1px",
|
|
2859
|
+
background: colors.border,
|
|
2860
|
+
minHeight: "200px"
|
|
2861
|
+
},
|
|
2862
|
+
children: [
|
|
2863
|
+
/* @__PURE__ */ jsx(
|
|
2864
|
+
"div",
|
|
2865
|
+
{
|
|
2866
|
+
css: {
|
|
2867
|
+
flex: 1,
|
|
2868
|
+
display: "flex",
|
|
2869
|
+
flexDirection: "column",
|
|
2870
|
+
background: colors.bg,
|
|
2871
|
+
overflow: "hidden"
|
|
2872
|
+
},
|
|
2873
|
+
children: [
|
|
2874
|
+
/* @__PURE__ */ jsx(
|
|
2875
|
+
"div",
|
|
2876
|
+
{
|
|
2877
|
+
css: {
|
|
2878
|
+
padding: "8px 12px",
|
|
2879
|
+
borderBottom: `1px solid ${colors.border}`,
|
|
2880
|
+
fontSize: "11px",
|
|
2881
|
+
fontWeight: 600,
|
|
2882
|
+
textTransform: "uppercase",
|
|
2883
|
+
letterSpacing: "0.5px",
|
|
2884
|
+
color: colors.textMuted,
|
|
2885
|
+
display: "flex",
|
|
2886
|
+
justifyContent: "space-between",
|
|
2887
|
+
alignItems: "center"
|
|
2888
|
+
},
|
|
2889
|
+
children: /* @__PURE__ */ jsx("span", { children: [
|
|
2890
|
+
"Unstaged (",
|
|
2891
|
+
unstaged.length,
|
|
2892
|
+
")"
|
|
2893
|
+
] })
|
|
2894
|
+
}
|
|
2895
|
+
),
|
|
2896
|
+
/* @__PURE__ */ jsx("div", { css: { flex: 1, overflow: "auto" }, children: [
|
|
2897
|
+
unstaged.map((file) => /* @__PURE__ */ jsx(
|
|
2898
|
+
StatusFileItem,
|
|
2899
|
+
{
|
|
2900
|
+
file,
|
|
2901
|
+
isSelected: selectedFile?.path === file.path && selectedFile?.type === "unstaged",
|
|
2902
|
+
onSelect: (signal) => selectFile(file.path, "unstaged", signal),
|
|
2903
|
+
onDoubleClick: () => handleStage([file.path])
|
|
2904
|
+
},
|
|
2905
|
+
file.path
|
|
2906
|
+
)),
|
|
2907
|
+
unstaged.length === 0 && /* @__PURE__ */ jsx(
|
|
2908
|
+
"div",
|
|
2909
|
+
{
|
|
2910
|
+
css: {
|
|
2911
|
+
padding: "12px",
|
|
2912
|
+
color: colors.textMuted,
|
|
2913
|
+
fontSize: "12px",
|
|
2914
|
+
textAlign: "center"
|
|
2915
|
+
},
|
|
2916
|
+
children: "No unstaged changes"
|
|
2917
|
+
}
|
|
2918
|
+
)
|
|
2919
|
+
] })
|
|
2920
|
+
]
|
|
2921
|
+
}
|
|
2922
|
+
),
|
|
2923
|
+
/* @__PURE__ */ jsx(
|
|
2924
|
+
"div",
|
|
2925
|
+
{
|
|
2926
|
+
css: {
|
|
2927
|
+
flex: 1,
|
|
2928
|
+
display: "flex",
|
|
2929
|
+
flexDirection: "column",
|
|
2930
|
+
background: colors.bg,
|
|
2931
|
+
overflow: "hidden"
|
|
2932
|
+
},
|
|
2933
|
+
children: [
|
|
2934
|
+
/* @__PURE__ */ jsx(
|
|
2935
|
+
"div",
|
|
2936
|
+
{
|
|
2937
|
+
css: {
|
|
2938
|
+
padding: "8px 12px",
|
|
2939
|
+
borderBottom: `1px solid ${colors.border}`,
|
|
2940
|
+
fontSize: "11px",
|
|
2941
|
+
fontWeight: 600,
|
|
2942
|
+
textTransform: "uppercase",
|
|
2943
|
+
letterSpacing: "0.5px",
|
|
2944
|
+
color: colors.textMuted
|
|
2945
|
+
},
|
|
2946
|
+
children: "Commit Message"
|
|
2947
|
+
}
|
|
2948
|
+
),
|
|
2949
|
+
/* @__PURE__ */ jsx(
|
|
2950
|
+
"div",
|
|
2951
|
+
{
|
|
2952
|
+
css: {
|
|
2953
|
+
flex: 1,
|
|
2954
|
+
display: "flex",
|
|
2955
|
+
flexDirection: "column",
|
|
2956
|
+
padding: "12px"
|
|
2957
|
+
},
|
|
2958
|
+
children: [
|
|
2959
|
+
/* @__PURE__ */ jsx(
|
|
2960
|
+
"textarea",
|
|
2961
|
+
{
|
|
2962
|
+
css: {
|
|
2963
|
+
flex: 1,
|
|
2964
|
+
resize: "none",
|
|
2965
|
+
border: `1px solid ${colors.border}`,
|
|
2966
|
+
borderRadius: "4px",
|
|
2967
|
+
padding: "8px",
|
|
2968
|
+
fontSize: "13px",
|
|
2969
|
+
fontFamily: "sf-mono, monospace",
|
|
2970
|
+
background: colors.bg,
|
|
2971
|
+
color: colors.text,
|
|
2972
|
+
"&:focus": {
|
|
2973
|
+
outline: "none",
|
|
2974
|
+
borderColor: colors.accent
|
|
2975
|
+
},
|
|
2976
|
+
"&::placeholder": {
|
|
2977
|
+
color: colors.textMuted
|
|
2978
|
+
}
|
|
2979
|
+
},
|
|
2980
|
+
placeholder: "Enter commit message...",
|
|
2981
|
+
value: commitMessage,
|
|
2982
|
+
on: {
|
|
2983
|
+
input: (e) => {
|
|
2984
|
+
commitMessage = e.currentTarget.value;
|
|
2985
|
+
handle.update();
|
|
2986
|
+
},
|
|
2987
|
+
keydown: (e) => {
|
|
2988
|
+
if (e.metaKey && e.key === "Enter") {
|
|
2989
|
+
e.preventDefault();
|
|
2990
|
+
handleCommit();
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2995
|
+
),
|
|
2996
|
+
/* @__PURE__ */ jsx(
|
|
2997
|
+
"div",
|
|
2998
|
+
{
|
|
2999
|
+
css: {
|
|
3000
|
+
display: "flex",
|
|
3001
|
+
alignItems: "center",
|
|
3002
|
+
justifyContent: "space-between",
|
|
3003
|
+
marginTop: "12px",
|
|
3004
|
+
gap: "12px"
|
|
3005
|
+
},
|
|
3006
|
+
children: [
|
|
3007
|
+
/* @__PURE__ */ jsx(
|
|
3008
|
+
"label",
|
|
3009
|
+
{
|
|
3010
|
+
css: {
|
|
3011
|
+
display: "flex",
|
|
3012
|
+
alignItems: "center",
|
|
3013
|
+
gap: "6px",
|
|
3014
|
+
fontSize: "12px"
|
|
3015
|
+
},
|
|
3016
|
+
children: [
|
|
3017
|
+
/* @__PURE__ */ jsx(
|
|
3018
|
+
"input",
|
|
3019
|
+
{
|
|
3020
|
+
type: "checkbox",
|
|
3021
|
+
checked: amend,
|
|
3022
|
+
on: {
|
|
3023
|
+
change: (e) => toggleAmend(e.currentTarget.checked)
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
),
|
|
3027
|
+
"Amend"
|
|
3028
|
+
]
|
|
3029
|
+
}
|
|
3030
|
+
),
|
|
3031
|
+
/* @__PURE__ */ jsx(
|
|
3032
|
+
"button",
|
|
3033
|
+
{
|
|
3034
|
+
css: {
|
|
3035
|
+
padding: "6px 16px",
|
|
3036
|
+
border: "none",
|
|
3037
|
+
borderRadius: "4px",
|
|
3038
|
+
background: displayStaged.length > 0 && commitMessage.trim() ? colors.accent : colors.bgLighter,
|
|
3039
|
+
color: displayStaged.length > 0 && commitMessage.trim() ? "#fff" : colors.textMuted,
|
|
3040
|
+
fontSize: "12px",
|
|
3041
|
+
fontWeight: 600,
|
|
3042
|
+
cursor: displayStaged.length > 0 && commitMessage.trim() ? "pointer" : "not-allowed",
|
|
3043
|
+
"&:hover": {
|
|
3044
|
+
background: displayStaged.length > 0 && commitMessage.trim() ? "#0860ca" : colors.bgLighter
|
|
3045
|
+
}
|
|
3046
|
+
},
|
|
3047
|
+
disabled: displayStaged.length === 0 || !commitMessage.trim() || loading,
|
|
3048
|
+
on: { click: handleCommit },
|
|
3049
|
+
children: loading ? "..." : "Commit"
|
|
3050
|
+
}
|
|
3051
|
+
)
|
|
3052
|
+
]
|
|
3053
|
+
}
|
|
3054
|
+
)
|
|
3055
|
+
]
|
|
3056
|
+
}
|
|
3057
|
+
)
|
|
3058
|
+
]
|
|
3059
|
+
}
|
|
3060
|
+
),
|
|
3061
|
+
/* @__PURE__ */ jsx(
|
|
3062
|
+
"div",
|
|
3063
|
+
{
|
|
3064
|
+
css: {
|
|
3065
|
+
flex: 1,
|
|
3066
|
+
display: "flex",
|
|
3067
|
+
flexDirection: "column",
|
|
3068
|
+
background: colors.bg,
|
|
3069
|
+
overflow: "hidden"
|
|
3070
|
+
},
|
|
3071
|
+
children: [
|
|
3072
|
+
/* @__PURE__ */ jsx(
|
|
3073
|
+
"div",
|
|
3074
|
+
{
|
|
3075
|
+
css: {
|
|
3076
|
+
padding: "8px 12px",
|
|
3077
|
+
borderBottom: `1px solid ${colors.border}`,
|
|
3078
|
+
fontSize: "11px",
|
|
3079
|
+
fontWeight: 600,
|
|
3080
|
+
textTransform: "uppercase",
|
|
3081
|
+
letterSpacing: "0.5px",
|
|
3082
|
+
color: colors.textMuted
|
|
3083
|
+
},
|
|
3084
|
+
children: [
|
|
3085
|
+
"Staged (",
|
|
3086
|
+
displayStaged.length,
|
|
3087
|
+
")"
|
|
3088
|
+
]
|
|
3089
|
+
}
|
|
3090
|
+
),
|
|
3091
|
+
/* @__PURE__ */ jsx("div", { css: { flex: 1, overflow: "auto" }, children: [
|
|
3092
|
+
displayStaged.map((file) => /* @__PURE__ */ jsx(
|
|
3093
|
+
StatusFileItem,
|
|
3094
|
+
{
|
|
3095
|
+
file,
|
|
3096
|
+
isSelected: selectedFile?.path === file.path && selectedFile?.type === "staged",
|
|
3097
|
+
onSelect: (signal) => selectFile(file.path, "staged", signal),
|
|
3098
|
+
onDoubleClick: () => handleUnstage([file.path])
|
|
3099
|
+
},
|
|
3100
|
+
file.path
|
|
3101
|
+
)),
|
|
3102
|
+
displayStaged.length === 0 && /* @__PURE__ */ jsx(
|
|
3103
|
+
"div",
|
|
3104
|
+
{
|
|
3105
|
+
css: {
|
|
3106
|
+
padding: "12px",
|
|
3107
|
+
color: colors.textMuted,
|
|
3108
|
+
fontSize: "12px",
|
|
3109
|
+
textAlign: "center"
|
|
3110
|
+
},
|
|
3111
|
+
children: "No staged changes"
|
|
3112
|
+
}
|
|
3113
|
+
)
|
|
3114
|
+
] })
|
|
3115
|
+
]
|
|
3116
|
+
}
|
|
3117
|
+
)
|
|
3118
|
+
]
|
|
3119
|
+
}
|
|
3120
|
+
)
|
|
3121
|
+
]
|
|
3122
|
+
}
|
|
3123
|
+
);
|
|
3124
|
+
};
|
|
3125
|
+
}
|
|
3126
|
+
function StatusFileItem() {
|
|
3127
|
+
return ({
|
|
3128
|
+
file,
|
|
3129
|
+
isSelected,
|
|
3130
|
+
onSelect,
|
|
3131
|
+
onDoubleClick
|
|
3132
|
+
}) => {
|
|
3133
|
+
let displayName = file.path.split("/").pop() ?? file.path;
|
|
3134
|
+
let statusLabel = {
|
|
3135
|
+
M: "MOD",
|
|
3136
|
+
A: "ADD",
|
|
3137
|
+
D: "DEL",
|
|
3138
|
+
R: "REN",
|
|
3139
|
+
"?": "NEW"
|
|
3140
|
+
}[file.status] ?? file.status;
|
|
3141
|
+
let statusColor = {
|
|
3142
|
+
M: colors.accent,
|
|
3143
|
+
A: colors.green,
|
|
3144
|
+
D: colors.red,
|
|
3145
|
+
R: colors.accent,
|
|
3146
|
+
"?": colors.green
|
|
3147
|
+
}[file.status] ?? colors.textMuted;
|
|
3148
|
+
return /* @__PURE__ */ jsx(
|
|
3149
|
+
"div",
|
|
3150
|
+
{
|
|
3151
|
+
css: {
|
|
3152
|
+
padding: "6px 12px",
|
|
3153
|
+
background: isSelected ? colors.accentDim : "transparent",
|
|
3154
|
+
userSelect: "none",
|
|
3155
|
+
"&:hover": {
|
|
3156
|
+
background: isSelected ? colors.accentDim : colors.bgLighter
|
|
3157
|
+
}
|
|
3158
|
+
},
|
|
3159
|
+
on: {
|
|
3160
|
+
click: (_, signal) => onSelect(signal),
|
|
3161
|
+
dblclick: onDoubleClick
|
|
3162
|
+
},
|
|
3163
|
+
children: [
|
|
3164
|
+
/* @__PURE__ */ jsx(
|
|
3165
|
+
"div",
|
|
3166
|
+
{
|
|
3167
|
+
css: {
|
|
3168
|
+
display: "flex",
|
|
3169
|
+
alignItems: "center",
|
|
3170
|
+
gap: "8px"
|
|
3171
|
+
},
|
|
3172
|
+
children: [
|
|
3173
|
+
/* @__PURE__ */ jsx(
|
|
3174
|
+
"span",
|
|
3175
|
+
{
|
|
3176
|
+
css: {
|
|
3177
|
+
fontSize: "9px",
|
|
3178
|
+
fontWeight: 600,
|
|
3179
|
+
padding: "2px 4px",
|
|
3180
|
+
borderRadius: "3px",
|
|
3181
|
+
background: statusColor,
|
|
3182
|
+
color: "#fff"
|
|
3183
|
+
},
|
|
3184
|
+
children: statusLabel
|
|
3185
|
+
}
|
|
3186
|
+
),
|
|
3187
|
+
/* @__PURE__ */ jsx(
|
|
3188
|
+
"span",
|
|
3189
|
+
{
|
|
3190
|
+
css: {
|
|
3191
|
+
flex: 1,
|
|
3192
|
+
overflow: "hidden",
|
|
3193
|
+
textOverflow: "ellipsis",
|
|
3194
|
+
whiteSpace: "nowrap",
|
|
3195
|
+
fontSize: "12px"
|
|
3196
|
+
},
|
|
3197
|
+
title: file.path,
|
|
3198
|
+
children: displayName
|
|
3199
|
+
}
|
|
3200
|
+
)
|
|
3201
|
+
]
|
|
3202
|
+
}
|
|
3203
|
+
),
|
|
3204
|
+
file.path !== displayName && /* @__PURE__ */ jsx(
|
|
3205
|
+
"div",
|
|
3206
|
+
{
|
|
3207
|
+
css: {
|
|
3208
|
+
fontSize: "10px",
|
|
3209
|
+
color: colors.textMuted,
|
|
3210
|
+
marginTop: "2px",
|
|
3211
|
+
marginLeft: "32px",
|
|
3212
|
+
overflow: "hidden",
|
|
3213
|
+
textOverflow: "ellipsis",
|
|
3214
|
+
whiteSpace: "nowrap"
|
|
3215
|
+
},
|
|
3216
|
+
children: file.path
|
|
3217
|
+
}
|
|
3218
|
+
)
|
|
3219
|
+
]
|
|
3220
|
+
}
|
|
3221
|
+
);
|
|
3222
|
+
};
|
|
3223
|
+
}
|
|
2538
3224
|
createRoot(document.body).render(/* @__PURE__ */ jsx(App, {}));
|
package/dist/server.js
CHANGED
|
@@ -9033,6 +9033,112 @@ function formatDate(date) {
|
|
|
9033
9033
|
minute: "2-digit"
|
|
9034
9034
|
});
|
|
9035
9035
|
}
|
|
9036
|
+
async function getStatus() {
|
|
9037
|
+
let output = await git("status --porcelain=v1");
|
|
9038
|
+
let lines = output ? output.split("\n").filter(Boolean) : [];
|
|
9039
|
+
let staged = [];
|
|
9040
|
+
let unstaged = [];
|
|
9041
|
+
for (let line of lines) {
|
|
9042
|
+
let indexStatus = line[0];
|
|
9043
|
+
let workTreeStatus = line[1];
|
|
9044
|
+
let path4 = line.slice(3);
|
|
9045
|
+
if (path4.includes(" -> ")) {
|
|
9046
|
+
path4 = path4.split(" -> ")[1];
|
|
9047
|
+
}
|
|
9048
|
+
if (indexStatus !== " " && indexStatus !== "?") {
|
|
9049
|
+
staged.push({ path: path4, status: indexStatus });
|
|
9050
|
+
}
|
|
9051
|
+
if (workTreeStatus !== " ") {
|
|
9052
|
+
let status = workTreeStatus === "?" ? "?" : workTreeStatus;
|
|
9053
|
+
unstaged.push({ path: path4, status });
|
|
9054
|
+
}
|
|
9055
|
+
}
|
|
9056
|
+
return { staged, unstaged };
|
|
9057
|
+
}
|
|
9058
|
+
async function stageFiles(paths) {
|
|
9059
|
+
if (paths.length === 0) return;
|
|
9060
|
+
let escaped = paths.map((p) => `"${p}"`).join(" ");
|
|
9061
|
+
await git(`add ${escaped}`);
|
|
9062
|
+
}
|
|
9063
|
+
async function unstageFiles(paths) {
|
|
9064
|
+
if (paths.length === 0) return;
|
|
9065
|
+
let escaped = paths.map((p) => `"${p}"`).join(" ");
|
|
9066
|
+
await git(`restore --staged ${escaped}`);
|
|
9067
|
+
}
|
|
9068
|
+
async function commitChanges(message, amend) {
|
|
9069
|
+
let escapedMessage = message.replace(/"/g, '\\"');
|
|
9070
|
+
let args = `commit -m "${escapedMessage}"`;
|
|
9071
|
+
if (amend) {
|
|
9072
|
+
args += " --amend";
|
|
9073
|
+
}
|
|
9074
|
+
await git(args);
|
|
9075
|
+
}
|
|
9076
|
+
async function getLastCommit() {
|
|
9077
|
+
let format = "%H%x1f%h%x1f%s%x1f%b";
|
|
9078
|
+
let metaOutput = await git(`log -1 --format="${format}"`);
|
|
9079
|
+
let [sha, shortSha, subject, body] = metaOutput.split("");
|
|
9080
|
+
let filesOutput = await git("diff-tree --no-commit-id --name-status -r HEAD");
|
|
9081
|
+
let files = [];
|
|
9082
|
+
if (filesOutput) {
|
|
9083
|
+
for (let line of filesOutput.split("\n").filter(Boolean)) {
|
|
9084
|
+
let [status, ...pathParts] = line.split(" ");
|
|
9085
|
+
let path4 = pathParts.join(" ");
|
|
9086
|
+
if (pathParts.length > 1) {
|
|
9087
|
+
path4 = pathParts[1];
|
|
9088
|
+
}
|
|
9089
|
+
files.push({ path: path4, status: status[0] });
|
|
9090
|
+
}
|
|
9091
|
+
}
|
|
9092
|
+
return {
|
|
9093
|
+
sha,
|
|
9094
|
+
shortSha,
|
|
9095
|
+
subject,
|
|
9096
|
+
body: body ? body.trimEnd() : "",
|
|
9097
|
+
files
|
|
9098
|
+
};
|
|
9099
|
+
}
|
|
9100
|
+
async function getWorkingDiff(filePath) {
|
|
9101
|
+
let output = await git(`diff -- "${filePath}"`);
|
|
9102
|
+
if (output) {
|
|
9103
|
+
return output;
|
|
9104
|
+
}
|
|
9105
|
+
try {
|
|
9106
|
+
let fileContent = fs2.readFileSync(path3.join(repoDir, filePath), "utf-8");
|
|
9107
|
+
let lines = fileContent.split("\n");
|
|
9108
|
+
let diffLines = [
|
|
9109
|
+
`diff --git a/${filePath} b/${filePath}`,
|
|
9110
|
+
`new file mode 100644`,
|
|
9111
|
+
`--- /dev/null`,
|
|
9112
|
+
`+++ b/${filePath}`,
|
|
9113
|
+
`@@ -0,0 +1,${lines.length} @@`,
|
|
9114
|
+
...lines.map((line) => `+${line}`)
|
|
9115
|
+
];
|
|
9116
|
+
return diffLines.join("\n");
|
|
9117
|
+
} catch {
|
|
9118
|
+
return "";
|
|
9119
|
+
}
|
|
9120
|
+
}
|
|
9121
|
+
async function getStagedDiff(filePath) {
|
|
9122
|
+
let output = await git(`diff --cached -- "${filePath}"`);
|
|
9123
|
+
if (output) {
|
|
9124
|
+
return output;
|
|
9125
|
+
}
|
|
9126
|
+
try {
|
|
9127
|
+
let fileContent = await git(`show :${filePath}`);
|
|
9128
|
+
let lines = fileContent.split("\n");
|
|
9129
|
+
let diffLines = [
|
|
9130
|
+
`diff --git a/${filePath} b/${filePath}`,
|
|
9131
|
+
`new file mode 100644`,
|
|
9132
|
+
`--- /dev/null`,
|
|
9133
|
+
`+++ b/${filePath}`,
|
|
9134
|
+
`@@ -0,0 +1,${lines.length} @@`,
|
|
9135
|
+
...lines.map((line) => `+${line}`)
|
|
9136
|
+
];
|
|
9137
|
+
return diffLines.join("\n");
|
|
9138
|
+
} catch {
|
|
9139
|
+
return "";
|
|
9140
|
+
}
|
|
9141
|
+
}
|
|
9036
9142
|
async function getDiff(sha) {
|
|
9037
9143
|
let format = "%H%x1f%h%x1f%s%x1f%b%x1f%an%x1f%ai%x1f%P";
|
|
9038
9144
|
let metaOutput = await git(`show -z --format="${format}" -s ${sha}`);
|
|
@@ -9102,9 +9208,102 @@ router.get("/api/diff/:sha", async ({ params }) => {
|
|
|
9102
9208
|
return Response.json({ error: "Failed to get diff" }, { status: 500 });
|
|
9103
9209
|
}
|
|
9104
9210
|
});
|
|
9211
|
+
router.get("/api/status", async () => {
|
|
9212
|
+
try {
|
|
9213
|
+
let status = await getStatus();
|
|
9214
|
+
return Response.json(status);
|
|
9215
|
+
} catch (error) {
|
|
9216
|
+
console.error("Error getting status:", error);
|
|
9217
|
+
return Response.json({ error: "Failed to get status" }, { status: 500 });
|
|
9218
|
+
}
|
|
9219
|
+
});
|
|
9220
|
+
router.post("/api/stage", async ({ request }) => {
|
|
9221
|
+
try {
|
|
9222
|
+
let { paths } = await request.json();
|
|
9223
|
+
await stageFiles(paths);
|
|
9224
|
+
return Response.json({ success: true });
|
|
9225
|
+
} catch (error) {
|
|
9226
|
+
console.error("Error staging files:", error);
|
|
9227
|
+
return Response.json({ error: "Failed to stage files" }, { status: 500 });
|
|
9228
|
+
}
|
|
9229
|
+
});
|
|
9230
|
+
router.post("/api/unstage", async ({ request }) => {
|
|
9231
|
+
try {
|
|
9232
|
+
let { paths } = await request.json();
|
|
9233
|
+
await unstageFiles(paths);
|
|
9234
|
+
return Response.json({ success: true });
|
|
9235
|
+
} catch (error) {
|
|
9236
|
+
console.error("Error unstaging files:", error);
|
|
9237
|
+
return Response.json({ error: "Failed to unstage files" }, { status: 500 });
|
|
9238
|
+
}
|
|
9239
|
+
});
|
|
9240
|
+
router.post("/api/commit", async ({ request }) => {
|
|
9241
|
+
try {
|
|
9242
|
+
let { message, amend } = await request.json();
|
|
9243
|
+
await commitChanges(message, amend || false);
|
|
9244
|
+
return Response.json({ success: true });
|
|
9245
|
+
} catch (error) {
|
|
9246
|
+
console.error("Error committing:", error);
|
|
9247
|
+
return Response.json({ error: "Failed to commit" }, { status: 500 });
|
|
9248
|
+
}
|
|
9249
|
+
});
|
|
9250
|
+
router.get("/api/last-commit", async () => {
|
|
9251
|
+
try {
|
|
9252
|
+
let lastCommit = await getLastCommit();
|
|
9253
|
+
return Response.json(lastCommit);
|
|
9254
|
+
} catch (error) {
|
|
9255
|
+
console.error("Error getting last commit:", error);
|
|
9256
|
+
return Response.json({ error: "Failed to get last commit" }, { status: 500 });
|
|
9257
|
+
}
|
|
9258
|
+
});
|
|
9259
|
+
router.get("/api/working-diff", async ({ url }) => {
|
|
9260
|
+
try {
|
|
9261
|
+
let filePath = url.searchParams.get("path");
|
|
9262
|
+
if (!filePath) {
|
|
9263
|
+
return Response.json({ error: "Missing path parameter" }, { status: 400 });
|
|
9264
|
+
}
|
|
9265
|
+
let diffOutput = await getWorkingDiff(filePath);
|
|
9266
|
+
let parsedDiff = (0, import_diff2html.parse)(diffOutput);
|
|
9267
|
+
let diffHtml = (0, import_diff2html.html)(parsedDiff, {
|
|
9268
|
+
drawFileList: false,
|
|
9269
|
+
outputFormat: "line-by-line",
|
|
9270
|
+
matching: "lines"
|
|
9271
|
+
});
|
|
9272
|
+
return Response.json({ diffHtml });
|
|
9273
|
+
} catch (error) {
|
|
9274
|
+
console.error("Error getting working diff:", error);
|
|
9275
|
+
return Response.json({ error: "Failed to get working diff" }, { status: 500 });
|
|
9276
|
+
}
|
|
9277
|
+
});
|
|
9278
|
+
router.get("/api/staged-diff", async ({ url }) => {
|
|
9279
|
+
try {
|
|
9280
|
+
let filePath = url.searchParams.get("path");
|
|
9281
|
+
if (!filePath) {
|
|
9282
|
+
return Response.json({ error: "Missing path parameter" }, { status: 400 });
|
|
9283
|
+
}
|
|
9284
|
+
let diffOutput = await getStagedDiff(filePath);
|
|
9285
|
+
let parsedDiff = (0, import_diff2html.parse)(diffOutput);
|
|
9286
|
+
let diffHtml = (0, import_diff2html.html)(parsedDiff, {
|
|
9287
|
+
drawFileList: false,
|
|
9288
|
+
outputFormat: "line-by-line",
|
|
9289
|
+
matching: "lines"
|
|
9290
|
+
});
|
|
9291
|
+
return Response.json({ diffHtml });
|
|
9292
|
+
} catch (error) {
|
|
9293
|
+
console.error("Error getting staged diff:", error);
|
|
9294
|
+
return Response.json({ error: "Failed to get staged diff" }, { status: 500 });
|
|
9295
|
+
}
|
|
9296
|
+
});
|
|
9105
9297
|
var server = http.createServer(
|
|
9106
9298
|
createRequestListener(async (request) => {
|
|
9107
|
-
|
|
9299
|
+
let response = await router.fetch(request);
|
|
9300
|
+
let headers = new Headers(response.headers);
|
|
9301
|
+
headers.set("Cache-Control", "no-store");
|
|
9302
|
+
return new Response(response.body, {
|
|
9303
|
+
status: response.status,
|
|
9304
|
+
statusText: response.statusText,
|
|
9305
|
+
headers
|
|
9306
|
+
});
|
|
9108
9307
|
})
|
|
9109
9308
|
);
|
|
9110
9309
|
var startPort = 44100;
|