Skip to content

Commit d5dd7b6

Browse files
committed
v0.7.23
- Add the /deepresearch command to conduct in-depth research and generate research reports, which are stored in the .snow/deepresearch/ folder at the root directory of the working directory - Add full coverage functionality for ROLE.md, access the ROLE list using the /role -l command, and use the shortcut key R to override the built-in system prompts of Snow CLI - Add the feature to switch between working directories, enhancing single-window flexibility, and use the /ide command to switch working directories - The skills panel has been migrated from the original mcp panel to a new independent panel management, access the skills list using the /skills -l command
1 parent 75a00df commit d5dd7b6

14 files changed

Lines changed: 395 additions & 115 deletions

File tree

.github/workflows/publish.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,11 @@ jobs:
5656
5757
### What's New
5858
59-
- Add the /models command for quick model switching
60-
59+
- Add the /deepresearch command to conduct in-depth research and generate research reports, which are stored in the .snow/deepresearch/ folder at the root directory of the working directory
60+
- Add full coverage functionality for ROLE.md, access the ROLE list using the /role -l command, and use the shortcut key R to override the built-in system prompts of Snow CLI
61+
- Add the feature to switch between working directories, enhancing single-window flexibility, and use the /ide command to switch working directories
62+
- The skills panel has been migrated from the original mcp panel to a new independent panel management, access the skills list using the /skills -l command
63+
6164
### Installation
6265
```bash
6366
npm install -g snow-ai

JetBrains/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ plugins {
55
}
66

77
group = "com.snow"
8-
version = "0.4.18"
8+
version = "0.4.19"
99

1010
repositories {
1111
mavenCentral()

JetBrains/src/main/kotlin/com/snow/plugin/SnowWebSocketManager.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import org.java_websocket.WebSocket
66
import org.java_websocket.handshake.ClientHandshake
77
import org.java_websocket.server.WebSocketServer
88
import java.net.InetSocketAddress
9+
import java.net.ServerSocket
910
import java.util.concurrent.ConcurrentHashMap
1011
import java.util.concurrent.atomic.AtomicReference
1112

@@ -70,6 +71,19 @@ class SnowWebSocketManager private constructor() {
7071
return
7172
}
7273

74+
// Synchronously probe whether the port is actually free before handing it
75+
// to Java-WebSocket. Java-WebSocket's start() is asynchronous: when another
76+
// process (e.g. another JetBrains IDE) already holds the port, the bind
77+
// failure surfaces only inside the server thread via onError, AFTER we have
78+
// already cached actualPort and registered the project under the wrong port
79+
// in snow-cli-ports.json. That mismatch is what causes the CLI to attach
80+
// to the WRONG IDE when two JetBrains IDEs are open simultaneously
81+
// (showing one IDE's active file with another IDE's working directory).
82+
if (!isPortAvailable(port)) {
83+
tryStartServer(port + 1)
84+
return
85+
}
86+
7387
try {
7488
val wsServer = WebSocketServerImpl(InetSocketAddress(port))
7589
server.set(wsServer)
@@ -99,6 +113,27 @@ class SnowWebSocketManager private constructor() {
99113
}
100114
}
101115

116+
/**
117+
* Test whether a TCP port can be bound on localhost. Used to avoid the
118+
* Java-WebSocket async-bind race: if another IDE already owns the port,
119+
* binding here fails immediately and we move on to the next port.
120+
*
121+
* Note: there is an inherent (microscopic) TOCTOU window between the probe
122+
* and the actual WebSocketServer bind. The async catch path above still
123+
* handles that fallback for completeness.
124+
*/
125+
private fun isPortAvailable(port: Int): Boolean {
126+
return try {
127+
ServerSocket().use { socket ->
128+
socket.reuseAddress = false
129+
socket.bind(InetSocketAddress("0.0.0.0", port))
130+
}
131+
true
132+
} catch (e: Exception) {
133+
false
134+
}
135+
}
136+
102137
/**
103138
* Write port information to temp file for a specific project.
104139
* Skips writing if the workspace path is empty to avoid

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "snow-ai",
3-
"version": "0.7.22",
3+
"version": "0.7.23",
44
"description": "Agentic coding in your terminal",
55
"license": "MIT",
66
"bin": {

source/i18n/lang/en.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,10 @@ export const en: TranslationKeys = {
747747
connectSuccess: 'Connected to {label}',
748748
connectError: 'Failed to connect: {error}',
749749
unmatchedIDEs:
750-
'Found {count} other running IDE(s). However, their workspace/project directories do not match the current cwd.',
750+
'The following {count} IDE(s) have workspaces that do not match the current directory. Selecting one will switch the working directory:',
751+
unmatchedHeader: '— Switch working directory —',
752+
switchWorkdirMark: ' (switch cwd)',
753+
switchWorkdirError: 'Failed to switch working directory: {error}',
751754
},
752755
permissionsPanel: {
753756
title: 'Permissions',

source/i18n/lang/zh-TW.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,10 @@ export const zhTW: TranslationKeys = {
703703
connectSuccess: '已連線至 {label}',
704704
connectError: '連線失敗:{error}',
705705
unmatchedIDEs:
706-
'發現 {count} 個其他執行中的 IDE,但其工作區/專案目錄與目前工作目錄不相符。',
706+
'以下 {count} 個 IDE 工作區與目前目錄不相符,選擇後將自動切換工作目錄:',
707+
unmatchedHeader: '— 切換工作目錄 —',
708+
switchWorkdirMark: ' (切換工作目錄)',
709+
switchWorkdirError: '切換工作目錄失敗:{error}',
707710
},
708711
permissionsPanel: {
709712
title: '權限',

source/i18n/lang/zh.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,10 @@ export const zh: TranslationKeys = {
702702
connectSuccess: '已连接到 {label}',
703703
connectError: '连接失败:{error}',
704704
unmatchedIDEs:
705-
'发现 {count} 个其他运行中的 IDE,但其工作区/项目目录与当前工作目录不匹配。',
705+
'以下 {count} 个 IDE 工作区与当前目录不匹配,选择后将自动切换工作目录:',
706+
unmatchedHeader: '— 切换工作目录 —',
707+
switchWorkdirMark: ' (切换工作目录)',
708+
switchWorkdirError: '切换工作目录失败:{error}',
706709
},
707710
permissionsPanel: {
708711
title: '权限',

source/i18n/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,9 @@ export type TranslationKeys = {
692692
connectSuccess: string;
693693
connectError: string;
694694
unmatchedIDEs: string;
695+
unmatchedHeader: string;
696+
switchWorkdirMark: string;
697+
switchWorkdirError: string;
695698
};
696699
// Profile Panel
697700
profilePanel: {

source/ui/components/chat/ChatFooter.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ type ChatFooterProps = {
147147
status: 'connected' | 'disconnected',
148148
message?: string,
149149
) => void;
150+
onIdeWorkingDirectoryChanged?: (newCwd: string) => void;
150151

151152
// Skills list panel props
152153
showSkillsListPanel: boolean;
@@ -432,6 +433,7 @@ const ChatFooter = React.memo(function ChatFooter(props: ChatFooterProps) {
432433
visible={props.showIdeSelectPanel}
433434
onClose={() => props.setShowIdeSelectPanel(false)}
434435
onConnectionChange={props.onIdeConnectionChange}
436+
onWorkingDirectoryChanged={props.onIdeWorkingDirectoryChanged}
435437
/>
436438
)}
437439

0 commit comments

Comments
 (0)