Skip to content

Commit dd12d30

Browse files
committed
v0.7.29
- Optimize system prompts to obtain more accurate system information - Fix the issue of "copy-last" not working remotely (requires client compatibility) - Optimize the flexibility of the websearch tool - Support using all tools after adding a remote directory with add-dir - Optimize the display effect of context compression - Some commands are allowed to be used in content - Optimize init to include a more comprehensive workflow
1 parent 3520fa2 commit dd12d30

9 files changed

Lines changed: 264 additions & 115 deletions

File tree

.github/workflows/publish.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,13 @@ jobs:
5656
5757
### What's New
5858
59-
- Added /goal command and related features
60-
- File list supports multiple selection with spaces
61-
- Optimized some display effects and memory leak issues
59+
- Optimize system prompts to obtain more accurate system information
60+
- Fix the issue of "copy-last" not working remotely (requires client compatibility)
61+
- Optimize the flexibility of the websearch tool
62+
- Support using all tools after adding a remote directory with add-dir
63+
- Optimize the display effect of context compression
64+
- Some commands are allowed to be used in content
65+
- Optimize init to include a more comprehensive workflow
6266
6367
### Installation
6468
```bash

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.28",
3+
"version": "0.7.29",
44
"description": "Agentic coding in your terminal",
55
"license": "MIT",
66
"bin": {

source/hooks/conversation/useCommandHandler.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,15 +1361,16 @@ export function useCommandHandler(options: CommandHandlerOptions) {
13611361
result.action === 'initProject' &&
13621362
result.prompt
13631363
) {
1364-
// Add command execution feedback
1364+
// Add command execution feedback; show truncated user prompt under
1365+
// the command tree node when args were provided.
13651366
const commandMessage: Message = {
13661367
role: 'command',
1367-
content: '',
1368+
content: result.message || '',
13681369
commandName: commandName,
13691370
};
13701371
options.setMessages(prev => [...prev, commandMessage]);
1371-
// Auto-send the prompt using basicModel, hide the prompt from UI
1372-
options.processMessage(result.prompt, undefined, true, true);
1372+
// Use advanced model for init workflow (requires tool calls), hide the prompt from UI
1373+
options.processMessage(result.prompt, undefined, false, true);
13731374
} else if (
13741375
result.success &&
13751376
result.action === 'startGoalLoop' &&

source/hooks/input/keyboard/utils/inlineCommandTrigger.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ export function findInlineCommandTrigger(
4444
}
4545
}
4646

47-
slashIndex = text.lastIndexOf('/', slashIndex - 1);
47+
// Avoid getting stuck on the first slash. String.lastIndexOf('/', -1)
48+
// can still return index 0, which previously caused an infinite loop for
49+
// inputs like "/help " or "/goal objective" once the command contained whitespace.
50+
slashIndex = slashIndex > 0 ? text.lastIndexOf('/', slashIndex - 1) : -1;
4851
}
4952

5053
return null;

source/hooks/ui/useCommandPanel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ export type CommandPanelCommand = {
3535
// key 为指令名(不含斜杠),value 为提示文本(不含前导空格)
3636
export const COMMAND_ARGS_HINTS: Record<string, string> = {
3737
branch: '[name]',
38-
fork: '[name]',
3938
resume: '[sessionId]',
4039
reindex: '[-force]',
4140
codebase: '[on|off|status]',
@@ -44,6 +43,7 @@ export const COMMAND_ARGS_HINTS: Record<string, string> = {
4443
'add-dir': '[path]',
4544
loop: '<interval> <prompt> | list | tasks | cancel <id>',
4645
goal: '<objective> [--budget=N] | pause | resume | clear | status',
46+
init: '[prompt]',
4747
role: '[-l|--list | -d|--delete]',
4848
skills: '[-l|--list]',
4949
'role-subagent': '[-l|--list | -d|--delete]',

source/ui/components/chat/ChatInput.tsx

Lines changed: 61 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
COMMAND_ARGS_HINTS,
2424
COMMAND_ARGS_OPTIONS,
2525
} from '../../../hooks/ui/useCommandPanel.js';
26+
import {isInlineInsertionCommand} from '../../../hooks/input/keyboard/utils/inlineCommandTrigger.js';
2627
import {useFilePicker} from '../../../hooks/picker/useFilePicker.js';
2728
import {useHistoryNavigation} from '../../../hooks/input/useHistoryNavigation.js';
2829
import {useClipboard} from '../../../hooks/input/useClipboard.js';
@@ -851,29 +852,38 @@ export default function ChatInput({
851852
return match[2] && match[2].length > 0 ? hint : ` ${hint}`;
852853
}, [buffer.text]);
853854

854-
// 当输入为以 `/cmd` 开头且 cmd 命中已注册指令时,计算高亮长度(含开头的 `/`)。
855-
// 用于在输入框中以主题色高亮“完整指令”片段,方便用户确认命令已被识别。
856-
const completedCommandLength = useMemo(() => {
857-
const text = buffer.text;
858-
if (!text.startsWith('/')) return 0;
859-
const match = text.match(/^\/([a-zA-Z0-9_-]+)(?:\s|$)/);
860-
if (!match) return 0;
861-
const cmd = match[1] ?? '';
862-
if (!cmd) return 0;
855+
// 计算可高亮的指令长度(含开头的 `/`)。
856+
// - 行首位置允许所有已注册指令;
857+
// - 内容中的内联位置只高亮真正支持内联插入的指令,避免把普通 `/help` 误标成可用内联指令。
858+
const getCommandHighlightLength = useMemo(() => {
863859
const allCommands = getAllCommands();
864-
// 精确匹配(如 /help、/clear、/branch ...)
865-
const exact = allCommands.some(c => c.name === cmd);
866-
if (exact) return 1 + cmd.length;
867-
// 前缀型指令(如 agent-、todo-、skills-):cmd 以 `name` 开头且长度更长
868-
const prefixHit = allCommands.some(
869-
c =>
870-
c.name.endsWith('-') &&
871-
cmd.length > c.name.length &&
872-
cmd.startsWith(c.name),
873-
);
874-
if (prefixHit) return 1 + cmd.length;
875-
return 0;
876-
}, [buffer.text, getAllCommands]);
860+
861+
return (text: string, inlineOnly: boolean): number => {
862+
if (!text.startsWith('/')) return 0;
863+
864+
const commandToken = text.slice(1).match(/^\S*/)?.[0] ?? '';
865+
if (!commandToken) return 0;
866+
867+
const availableCommands = inlineOnly
868+
? allCommands.filter(isInlineInsertionCommand)
869+
: allCommands;
870+
const exact = availableCommands.some(c => c.name === commandToken);
871+
if (exact) return 1 + commandToken.length;
872+
873+
if (inlineOnly) return 0;
874+
875+
// 前缀型指令(如 agent-、todo-、skills-):cmd 以 `name` 开头且长度更长
876+
const prefixHit = availableCommands.some(
877+
c =>
878+
c.name.endsWith('-') &&
879+
commandToken.length > c.name.length &&
880+
commandToken.startsWith(c.name),
881+
);
882+
if (prefixHit) return 1 + commandToken.length;
883+
884+
return 0;
885+
};
886+
}, [getAllCommands]);
877887

878888
const renderContent = () => {
879889
if (buffer.text.length > 0) {
@@ -916,9 +926,10 @@ export default function ChatInput({
916926
}
917927

918928
// 渲染单行内容的辅助函数:同时高亮
919-
// 1. 首行已识别的完整指令 `/cmd`
920-
// 2. 各类 `[...]` 占位符标签(Paste / image / Skill / GitLine / » running-agent)
921-
// 3. `#agent_xxx` 裸文本子代理标签(词边界上)
929+
// 1. 已识别的行首完整指令 `/cmd`
930+
// 2. 内容中支持内联插入的指令(如 `/gitline`、Prompt 类型自定义指令)
931+
// 3. 各类 `[...]` 占位符标签(Paste / image / Skill / GitLine / » running-agent)
932+
// 4. `#agent_xxx` 裸文本子代理标签(词边界上)
922933
const renderLineSegments = (line: string, isFirstLine: boolean) => {
923934
type Token = {text: string; highlight: boolean};
924935
const tokens: Token[] = [];
@@ -930,32 +941,40 @@ export default function ChatInput({
930941
}
931942
};
932943

933-
let i = 0;
934-
935-
// 1) 首行完整指令高亮
936-
if (
937-
isFirstLine &&
938-
completedCommandLength > 0 &&
939-
line.length >= completedCommandLength
940-
) {
941-
tokens.push({
942-
text: line.slice(0, completedCommandLength),
943-
highlight: true,
944-
});
945-
i = completedCommandLength;
946-
}
947-
948944
const isPlaceholderTag = (tag: string) =>
949945
/^\[Paste \d+ lines #\d+\]$/.test(tag) ||
950946
/^\[image #\d+\]$/.test(tag) ||
951947
/^\[Skill:[^\]]+\]$/.test(tag) ||
952948
/^\[GitLine:[^\]]+\]$/.test(tag) ||
953949
/^\[»[^\]]*\]$/.test(tag);
954950

951+
let i = 0;
955952
while (i < line.length) {
956953
const ch = line[i];
957954

958-
// 2) [...] 占位符标签
955+
// 1/2) slash 指令高亮:行首允许所有指令,内容中只允许可内联插入指令。
956+
if (ch === '/') {
957+
const prevCh = i === 0 ? '' : line[i - 1] ?? '';
958+
const leftBoundary = i === 0 || /\s/.test(prevCh);
959+
if (leftBoundary) {
960+
const isRootCommandPosition = isFirstLine && i === 0;
961+
const commandLength = getCommandHighlightLength(
962+
line.slice(i),
963+
!isRootCommandPosition,
964+
);
965+
if (commandLength > 0) {
966+
flushPlain();
967+
tokens.push({
968+
text: line.slice(i, i + commandLength),
969+
highlight: true,
970+
});
971+
i += commandLength;
972+
continue;
973+
}
974+
}
975+
}
976+
977+
// 3) [...] 占位符标签
959978
if (ch === '[') {
960979
const closeIdx = line.indexOf(']', i + 1);
961980
if (closeIdx !== -1) {
@@ -970,7 +989,7 @@ export default function ChatInput({
970989
}
971990
}
972991

973-
// 3) #agent 裸文本标签:需要词边界(前面是行首或空白,后面是行末或空白)
992+
// 4) #agent 裸文本标签:需要词边界(前面是行首或空白,后面是行末或空白)
974993
if (ch === '#') {
975994
const prevCh = i === 0 ? '' : line[i - 1] ?? '';
976995
const leftBoundary = i === 0 || /\s/.test(prevCh);

source/utils/commands/branch.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,4 @@ registerCommand('branch', {
1414
},
1515
});
1616

17-
registerCommand('fork', {
18-
execute: (args?: string): CommandResult => {
19-
const branchName = args?.trim() || undefined;
20-
return {
21-
success: true,
22-
action: 'forkSession',
23-
prompt: branchName,
24-
};
25-
},
26-
});
27-
2817
export default {};

0 commit comments

Comments
 (0)