stashes 0.1.28 → 0.1.29
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/cli.js +76 -14
- package/dist/mcp.js +76 -14
- package/dist/web/assets/{index-DFTLJjq2.js → index-CBnXcjSs.js} +8 -8
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1537,7 +1537,10 @@ class StashService {
|
|
|
1537
1537
|
selectedComponent = null;
|
|
1538
1538
|
messageQueue = [];
|
|
1539
1539
|
isProcessingMessage = false;
|
|
1540
|
+
activeChatId = null;
|
|
1540
1541
|
chatSessions = new Map;
|
|
1542
|
+
stashPollTimer = null;
|
|
1543
|
+
knownStashIds = new Set;
|
|
1541
1544
|
constructor(projectPath, worktreeManager, persistence, broadcast) {
|
|
1542
1545
|
this.projectPath = projectPath;
|
|
1543
1546
|
this.worktreeManager = worktreeManager;
|
|
@@ -1545,6 +1548,9 @@ class StashService {
|
|
|
1545
1548
|
this.broadcast = broadcast;
|
|
1546
1549
|
this.previewPool = new PreviewPool(worktreeManager, broadcast);
|
|
1547
1550
|
}
|
|
1551
|
+
getActiveChatId() {
|
|
1552
|
+
return this.activeChatId;
|
|
1553
|
+
}
|
|
1548
1554
|
setSelectedComponent(component) {
|
|
1549
1555
|
this.selectedComponent = component;
|
|
1550
1556
|
if (component.filePath === "auto-detect") {
|
|
@@ -1599,8 +1605,10 @@ class StashService {
|
|
|
1599
1605
|
this.isProcessingMessage = true;
|
|
1600
1606
|
while (this.messageQueue.length > 0) {
|
|
1601
1607
|
const msg = this.messageQueue.shift();
|
|
1608
|
+
this.activeChatId = msg.chatId;
|
|
1602
1609
|
await this.processMessage(msg.projectId, msg.chatId, msg.message, msg.referenceStashIds, msg.componentContext);
|
|
1603
1610
|
}
|
|
1611
|
+
this.activeChatId = null;
|
|
1604
1612
|
this.isProcessingMessage = false;
|
|
1605
1613
|
}
|
|
1606
1614
|
async processMessage(projectId, chatId, message, referenceStashIds, componentContext) {
|
|
@@ -1660,20 +1668,22 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1660
1668
|
const aiProcess = startAiProcess("chat", chatPrompt, this.projectPath, existingSessionId);
|
|
1661
1669
|
let thinkingBuf = "";
|
|
1662
1670
|
let textBuf = "";
|
|
1663
|
-
const pendingMessages = [];
|
|
1664
1671
|
const now = new Date().toISOString();
|
|
1665
|
-
|
|
1672
|
+
const save = (msg) => {
|
|
1673
|
+
this.persistence.saveChatMessage(projectId, chatId, msg);
|
|
1674
|
+
};
|
|
1675
|
+
const flushThinking = () => {
|
|
1666
1676
|
if (!thinkingBuf)
|
|
1667
1677
|
return;
|
|
1668
|
-
|
|
1678
|
+
save({ id: crypto.randomUUID(), role: "assistant", content: thinkingBuf, type: "thinking", createdAt: now });
|
|
1669
1679
|
thinkingBuf = "";
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1680
|
+
};
|
|
1681
|
+
const flushText = () => {
|
|
1672
1682
|
if (!textBuf)
|
|
1673
1683
|
return;
|
|
1674
|
-
|
|
1684
|
+
save({ id: crypto.randomUUID(), role: "assistant", content: textBuf, type: "text", createdAt: now });
|
|
1675
1685
|
textBuf = "";
|
|
1676
|
-
}
|
|
1686
|
+
};
|
|
1677
1687
|
try {
|
|
1678
1688
|
for await (const chunk of parseClaudeStream(aiProcess.process)) {
|
|
1679
1689
|
if (chunk.type === "session_id" && chunk.sessionId) {
|
|
@@ -1707,7 +1717,7 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1707
1717
|
toolName = parsed.tool ?? "unknown";
|
|
1708
1718
|
toolParams = parsed.input ?? {};
|
|
1709
1719
|
} catch {}
|
|
1710
|
-
|
|
1720
|
+
save({
|
|
1711
1721
|
id: crypto.randomUUID(),
|
|
1712
1722
|
role: "assistant",
|
|
1713
1723
|
content: chunk.content,
|
|
@@ -1726,7 +1736,11 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1726
1736
|
toolParams,
|
|
1727
1737
|
toolStatus: "running"
|
|
1728
1738
|
});
|
|
1739
|
+
if (toolName.includes("stashes_generate") || toolName.includes("stashes_vary")) {
|
|
1740
|
+
this.startStashPoll(projectId, chatId);
|
|
1741
|
+
}
|
|
1729
1742
|
} else if (chunk.type === "tool_result") {
|
|
1743
|
+
this.stopStashPoll();
|
|
1730
1744
|
let toolResult = chunk.content;
|
|
1731
1745
|
let isError = false;
|
|
1732
1746
|
try {
|
|
@@ -1734,7 +1748,7 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1734
1748
|
toolResult = parsed.result ?? chunk.content;
|
|
1735
1749
|
isError = !!parsed.is_error;
|
|
1736
1750
|
} catch {}
|
|
1737
|
-
|
|
1751
|
+
save({
|
|
1738
1752
|
id: crypto.randomUUID(),
|
|
1739
1753
|
role: "assistant",
|
|
1740
1754
|
content: chunk.content,
|
|
@@ -1756,10 +1770,7 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1756
1770
|
await aiProcess.process.exited;
|
|
1757
1771
|
flushThinking();
|
|
1758
1772
|
flushText();
|
|
1759
|
-
|
|
1760
|
-
this.persistence.saveChatMessage(projectId, chatId, msg);
|
|
1761
|
-
}
|
|
1762
|
-
this.syncStashesFromDisk(projectId);
|
|
1773
|
+
this.syncStashesFromDisk(projectId, chatId);
|
|
1763
1774
|
} catch (err) {
|
|
1764
1775
|
this.broadcast({
|
|
1765
1776
|
type: "ai_stream",
|
|
@@ -1768,12 +1779,17 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1768
1779
|
source: "chat"
|
|
1769
1780
|
});
|
|
1770
1781
|
} finally {
|
|
1782
|
+
this.stopStashPoll();
|
|
1771
1783
|
killAiProcess("chat");
|
|
1772
1784
|
}
|
|
1773
1785
|
}
|
|
1774
|
-
syncStashesFromDisk(projectId) {
|
|
1786
|
+
syncStashesFromDisk(projectId, chatId) {
|
|
1775
1787
|
const diskStashes = this.persistence.listStashes(projectId);
|
|
1776
1788
|
for (const stash of diskStashes) {
|
|
1789
|
+
if (chatId && !stash.originChatId && !this.knownStashIds.has(stash.id)) {
|
|
1790
|
+
const updated = { ...stash, originChatId: chatId };
|
|
1791
|
+
this.persistence.saveStash(updated);
|
|
1792
|
+
}
|
|
1777
1793
|
this.broadcast({
|
|
1778
1794
|
type: "stash:status",
|
|
1779
1795
|
stashId: stash.id,
|
|
@@ -1788,6 +1804,48 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1788
1804
|
screenshots: stash.screenshots?.length ? [...stash.screenshots] : undefined
|
|
1789
1805
|
});
|
|
1790
1806
|
}
|
|
1807
|
+
this.knownStashIds.add(stash.id);
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
startStashPoll(projectId, chatId) {
|
|
1811
|
+
this.stopStashPoll();
|
|
1812
|
+
const lastStatus = new Map;
|
|
1813
|
+
for (const s of this.persistence.listStashes(projectId)) {
|
|
1814
|
+
this.knownStashIds.add(s.id);
|
|
1815
|
+
lastStatus.set(s.id, s.status);
|
|
1816
|
+
}
|
|
1817
|
+
this.stashPollTimer = setInterval(() => {
|
|
1818
|
+
const stashes = this.persistence.listStashes(projectId);
|
|
1819
|
+
for (const stash of stashes) {
|
|
1820
|
+
const prev = lastStatus.get(stash.id);
|
|
1821
|
+
if (!prev || prev !== stash.status) {
|
|
1822
|
+
if (chatId && !stash.originChatId && !prev) {
|
|
1823
|
+
this.persistence.saveStash({ ...stash, originChatId: chatId });
|
|
1824
|
+
}
|
|
1825
|
+
this.broadcast({
|
|
1826
|
+
type: "stash:status",
|
|
1827
|
+
stashId: stash.id,
|
|
1828
|
+
status: stash.status,
|
|
1829
|
+
number: stash.number
|
|
1830
|
+
});
|
|
1831
|
+
if (stash.screenshotUrl && prev !== stash.status) {
|
|
1832
|
+
this.broadcast({
|
|
1833
|
+
type: "stash:screenshot",
|
|
1834
|
+
stashId: stash.id,
|
|
1835
|
+
url: stash.screenshotUrl,
|
|
1836
|
+
screenshots: stash.screenshots?.length ? [...stash.screenshots] : undefined
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
lastStatus.set(stash.id, stash.status);
|
|
1840
|
+
this.knownStashIds.add(stash.id);
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
}, 2000);
|
|
1844
|
+
}
|
|
1845
|
+
stopStashPoll() {
|
|
1846
|
+
if (this.stashPollTimer) {
|
|
1847
|
+
clearInterval(this.stashPollTimer);
|
|
1848
|
+
this.stashPollTimer = null;
|
|
1791
1849
|
}
|
|
1792
1850
|
}
|
|
1793
1851
|
progressToBroadcast(event) {
|
|
@@ -1914,6 +1972,10 @@ function createWebSocketHandler(projectPath, userDevPort, appProxyPort) {
|
|
|
1914
1972
|
projectId: project.id,
|
|
1915
1973
|
projectName: project.name
|
|
1916
1974
|
}));
|
|
1975
|
+
const activeChatId = stashService.getActiveChatId();
|
|
1976
|
+
if (activeChatId) {
|
|
1977
|
+
ws.send(JSON.stringify({ type: "processing", chatId: activeChatId }));
|
|
1978
|
+
}
|
|
1917
1979
|
},
|
|
1918
1980
|
async message(ws, message) {
|
|
1919
1981
|
const raw = typeof message === "string" ? message : new TextDecoder().decode(message);
|
package/dist/mcp.js
CHANGED
|
@@ -1733,7 +1733,10 @@ class StashService {
|
|
|
1733
1733
|
selectedComponent = null;
|
|
1734
1734
|
messageQueue = [];
|
|
1735
1735
|
isProcessingMessage = false;
|
|
1736
|
+
activeChatId = null;
|
|
1736
1737
|
chatSessions = new Map;
|
|
1738
|
+
stashPollTimer = null;
|
|
1739
|
+
knownStashIds = new Set;
|
|
1737
1740
|
constructor(projectPath, worktreeManager, persistence, broadcast) {
|
|
1738
1741
|
this.projectPath = projectPath;
|
|
1739
1742
|
this.worktreeManager = worktreeManager;
|
|
@@ -1741,6 +1744,9 @@ class StashService {
|
|
|
1741
1744
|
this.broadcast = broadcast;
|
|
1742
1745
|
this.previewPool = new PreviewPool(worktreeManager, broadcast);
|
|
1743
1746
|
}
|
|
1747
|
+
getActiveChatId() {
|
|
1748
|
+
return this.activeChatId;
|
|
1749
|
+
}
|
|
1744
1750
|
setSelectedComponent(component) {
|
|
1745
1751
|
this.selectedComponent = component;
|
|
1746
1752
|
if (component.filePath === "auto-detect") {
|
|
@@ -1795,8 +1801,10 @@ class StashService {
|
|
|
1795
1801
|
this.isProcessingMessage = true;
|
|
1796
1802
|
while (this.messageQueue.length > 0) {
|
|
1797
1803
|
const msg = this.messageQueue.shift();
|
|
1804
|
+
this.activeChatId = msg.chatId;
|
|
1798
1805
|
await this.processMessage(msg.projectId, msg.chatId, msg.message, msg.referenceStashIds, msg.componentContext);
|
|
1799
1806
|
}
|
|
1807
|
+
this.activeChatId = null;
|
|
1800
1808
|
this.isProcessingMessage = false;
|
|
1801
1809
|
}
|
|
1802
1810
|
async processMessage(projectId, chatId, message, referenceStashIds, componentContext) {
|
|
@@ -1856,20 +1864,22 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1856
1864
|
const aiProcess = startAiProcess("chat", chatPrompt, this.projectPath, existingSessionId);
|
|
1857
1865
|
let thinkingBuf = "";
|
|
1858
1866
|
let textBuf = "";
|
|
1859
|
-
const pendingMessages = [];
|
|
1860
1867
|
const now = new Date().toISOString();
|
|
1861
|
-
|
|
1868
|
+
const save = (msg) => {
|
|
1869
|
+
this.persistence.saveChatMessage(projectId, chatId, msg);
|
|
1870
|
+
};
|
|
1871
|
+
const flushThinking = () => {
|
|
1862
1872
|
if (!thinkingBuf)
|
|
1863
1873
|
return;
|
|
1864
|
-
|
|
1874
|
+
save({ id: crypto.randomUUID(), role: "assistant", content: thinkingBuf, type: "thinking", createdAt: now });
|
|
1865
1875
|
thinkingBuf = "";
|
|
1866
|
-
}
|
|
1867
|
-
|
|
1876
|
+
};
|
|
1877
|
+
const flushText = () => {
|
|
1868
1878
|
if (!textBuf)
|
|
1869
1879
|
return;
|
|
1870
|
-
|
|
1880
|
+
save({ id: crypto.randomUUID(), role: "assistant", content: textBuf, type: "text", createdAt: now });
|
|
1871
1881
|
textBuf = "";
|
|
1872
|
-
}
|
|
1882
|
+
};
|
|
1873
1883
|
try {
|
|
1874
1884
|
for await (const chunk of parseClaudeStream(aiProcess.process)) {
|
|
1875
1885
|
if (chunk.type === "session_id" && chunk.sessionId) {
|
|
@@ -1903,7 +1913,7 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1903
1913
|
toolName = parsed.tool ?? "unknown";
|
|
1904
1914
|
toolParams = parsed.input ?? {};
|
|
1905
1915
|
} catch {}
|
|
1906
|
-
|
|
1916
|
+
save({
|
|
1907
1917
|
id: crypto.randomUUID(),
|
|
1908
1918
|
role: "assistant",
|
|
1909
1919
|
content: chunk.content,
|
|
@@ -1922,7 +1932,11 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1922
1932
|
toolParams,
|
|
1923
1933
|
toolStatus: "running"
|
|
1924
1934
|
});
|
|
1935
|
+
if (toolName.includes("stashes_generate") || toolName.includes("stashes_vary")) {
|
|
1936
|
+
this.startStashPoll(projectId, chatId);
|
|
1937
|
+
}
|
|
1925
1938
|
} else if (chunk.type === "tool_result") {
|
|
1939
|
+
this.stopStashPoll();
|
|
1926
1940
|
let toolResult = chunk.content;
|
|
1927
1941
|
let isError = false;
|
|
1928
1942
|
try {
|
|
@@ -1930,7 +1944,7 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1930
1944
|
toolResult = parsed.result ?? chunk.content;
|
|
1931
1945
|
isError = !!parsed.is_error;
|
|
1932
1946
|
} catch {}
|
|
1933
|
-
|
|
1947
|
+
save({
|
|
1934
1948
|
id: crypto.randomUUID(),
|
|
1935
1949
|
role: "assistant",
|
|
1936
1950
|
content: chunk.content,
|
|
@@ -1952,10 +1966,7 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1952
1966
|
await aiProcess.process.exited;
|
|
1953
1967
|
flushThinking();
|
|
1954
1968
|
flushText();
|
|
1955
|
-
|
|
1956
|
-
this.persistence.saveChatMessage(projectId, chatId, msg);
|
|
1957
|
-
}
|
|
1958
|
-
this.syncStashesFromDisk(projectId);
|
|
1969
|
+
this.syncStashesFromDisk(projectId, chatId);
|
|
1959
1970
|
} catch (err) {
|
|
1960
1971
|
this.broadcast({
|
|
1961
1972
|
type: "ai_stream",
|
|
@@ -1964,12 +1975,17 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1964
1975
|
source: "chat"
|
|
1965
1976
|
});
|
|
1966
1977
|
} finally {
|
|
1978
|
+
this.stopStashPoll();
|
|
1967
1979
|
killAiProcess("chat");
|
|
1968
1980
|
}
|
|
1969
1981
|
}
|
|
1970
|
-
syncStashesFromDisk(projectId) {
|
|
1982
|
+
syncStashesFromDisk(projectId, chatId) {
|
|
1971
1983
|
const diskStashes = this.persistence.listStashes(projectId);
|
|
1972
1984
|
for (const stash of diskStashes) {
|
|
1985
|
+
if (chatId && !stash.originChatId && !this.knownStashIds.has(stash.id)) {
|
|
1986
|
+
const updated = { ...stash, originChatId: chatId };
|
|
1987
|
+
this.persistence.saveStash(updated);
|
|
1988
|
+
}
|
|
1973
1989
|
this.broadcast({
|
|
1974
1990
|
type: "stash:status",
|
|
1975
1991
|
stashId: stash.id,
|
|
@@ -1984,6 +2000,48 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1984
2000
|
screenshots: stash.screenshots?.length ? [...stash.screenshots] : undefined
|
|
1985
2001
|
});
|
|
1986
2002
|
}
|
|
2003
|
+
this.knownStashIds.add(stash.id);
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
startStashPoll(projectId, chatId) {
|
|
2007
|
+
this.stopStashPoll();
|
|
2008
|
+
const lastStatus = new Map;
|
|
2009
|
+
for (const s of this.persistence.listStashes(projectId)) {
|
|
2010
|
+
this.knownStashIds.add(s.id);
|
|
2011
|
+
lastStatus.set(s.id, s.status);
|
|
2012
|
+
}
|
|
2013
|
+
this.stashPollTimer = setInterval(() => {
|
|
2014
|
+
const stashes = this.persistence.listStashes(projectId);
|
|
2015
|
+
for (const stash of stashes) {
|
|
2016
|
+
const prev = lastStatus.get(stash.id);
|
|
2017
|
+
if (!prev || prev !== stash.status) {
|
|
2018
|
+
if (chatId && !stash.originChatId && !prev) {
|
|
2019
|
+
this.persistence.saveStash({ ...stash, originChatId: chatId });
|
|
2020
|
+
}
|
|
2021
|
+
this.broadcast({
|
|
2022
|
+
type: "stash:status",
|
|
2023
|
+
stashId: stash.id,
|
|
2024
|
+
status: stash.status,
|
|
2025
|
+
number: stash.number
|
|
2026
|
+
});
|
|
2027
|
+
if (stash.screenshotUrl && prev !== stash.status) {
|
|
2028
|
+
this.broadcast({
|
|
2029
|
+
type: "stash:screenshot",
|
|
2030
|
+
stashId: stash.id,
|
|
2031
|
+
url: stash.screenshotUrl,
|
|
2032
|
+
screenshots: stash.screenshots?.length ? [...stash.screenshots] : undefined
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
lastStatus.set(stash.id, stash.status);
|
|
2036
|
+
this.knownStashIds.add(stash.id);
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
}, 2000);
|
|
2040
|
+
}
|
|
2041
|
+
stopStashPoll() {
|
|
2042
|
+
if (this.stashPollTimer) {
|
|
2043
|
+
clearInterval(this.stashPollTimer);
|
|
2044
|
+
this.stashPollTimer = null;
|
|
1987
2045
|
}
|
|
1988
2046
|
}
|
|
1989
2047
|
progressToBroadcast(event) {
|
|
@@ -2110,6 +2168,10 @@ function createWebSocketHandler(projectPath, userDevPort, appProxyPort) {
|
|
|
2110
2168
|
projectId: project.id,
|
|
2111
2169
|
projectName: project.name
|
|
2112
2170
|
}));
|
|
2171
|
+
const activeChatId = stashService.getActiveChatId();
|
|
2172
|
+
if (activeChatId) {
|
|
2173
|
+
ws.send(JSON.stringify({ type: "processing", chatId: activeChatId }));
|
|
2174
|
+
}
|
|
2113
2175
|
},
|
|
2114
2176
|
async message(ws, message) {
|
|
2115
2177
|
const raw = typeof message === "string" ? message : new TextDecoder().decode(message);
|