feat: restyle utility panel and streaming focus
This commit is contained in:
parent
79a90f4fad
commit
931a0488cc
@ -536,7 +536,7 @@ class WebTerminal(MainTerminal):
|
||||
|
||||
|
||||
# 如果是聚焦操作,广播聚焦文件更新
|
||||
if tool_name in ['focus_file', 'unfocus_file', 'modify_file']:
|
||||
if tool_name in ['focus_file', 'unfocus_file', 'modify_file', 'append_to_file']:
|
||||
try:
|
||||
focused_files_dict = self.get_focused_files_info()
|
||||
self.broadcast('focused_files_update', focused_files_dict)
|
||||
|
||||
1
static/icons/layers.svg
Normal file
1
static/icons/layers.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="48" height="48" fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="opacity:1;"><path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z"/><path d="M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12"/><path d="M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17"/></svg>
|
||||
|
After Width: | Height: | Size: 491 B |
@ -37,10 +37,11 @@
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div class="main-container">
|
||||
<div :class="['main-container', { 'utility-panel-hidden': utilityPanelHidden }]">
|
||||
<ConversationSidebar
|
||||
:icon-style="iconStyle"
|
||||
:format-time="formatTime"
|
||||
:utility-panel-hidden="utilityPanelHidden"
|
||||
@toggle="toggleSidebar"
|
||||
@create="createNewConversation"
|
||||
@search="handleSidebarSearch"
|
||||
@ -49,6 +50,7 @@
|
||||
@personal="openPersonalPage"
|
||||
@delete="deleteConversation"
|
||||
@duplicate="duplicateConversation"
|
||||
@toggle-utility-panel="toggleUtilityPanelVisibility"
|
||||
/>
|
||||
|
||||
<LeftPanel
|
||||
@ -60,12 +62,14 @@
|
||||
:is-connected="isConnected"
|
||||
:panel-menu-open="panelMenuOpen"
|
||||
:panel-mode="panelMode"
|
||||
:hidden="utilityPanelHidden"
|
||||
@toggle-panel-menu="togglePanelMenu"
|
||||
@select-panel="selectPanelMode"
|
||||
@open-file-manager="openGuiFileManager"
|
||||
@toggle-mode="toggleThinkingMode"
|
||||
/>
|
||||
|
||||
<div class="resize-handle" @mousedown="startResize('left', $event)"></div>
|
||||
<div v-if="!utilityPanelHidden" class="resize-handle" @mousedown="startResize('left', $event)"></div>
|
||||
|
||||
<main class="chat-container">
|
||||
<TokenDrawer
|
||||
|
||||
@ -192,6 +192,7 @@ const appOptions = {
|
||||
...mapState(useFileStore, ['contextMenu', 'fileTree', 'expandedFolders', 'todoList']),
|
||||
...mapWritableState(useUiStore, [
|
||||
'sidebarCollapsed',
|
||||
'utilityPanelHidden',
|
||||
'panelMode',
|
||||
'panelMenuOpen',
|
||||
'leftWidth',
|
||||
@ -314,6 +315,8 @@ const appOptions = {
|
||||
uiSetPanelMode: 'setPanelMode',
|
||||
uiSetPanelMenuOpen: 'setPanelMenuOpen',
|
||||
uiTogglePanelMenu: 'togglePanelMenu',
|
||||
uiToggleUtilityPanelHidden: 'toggleUtilityPanelHidden',
|
||||
uiSetUtilityPanelHidden: 'setUtilityPanelHidden',
|
||||
uiPushToast: 'pushToast',
|
||||
uiUpdateToast: 'updateToast',
|
||||
uiDismissToast: 'dismissToast',
|
||||
@ -1613,6 +1616,9 @@ const appOptions = {
|
||||
toggleSidebar() {
|
||||
this.uiToggleSidebar();
|
||||
},
|
||||
toggleUtilityPanelVisibility() {
|
||||
this.uiToggleUtilityPanelHidden();
|
||||
},
|
||||
|
||||
togglePanelMenu() {
|
||||
this.uiTogglePanelMenu();
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { computed, onMounted, watch } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useFocusStore } from '@/stores/focus';
|
||||
|
||||
@ -44,4 +44,23 @@ const focusedCount = computed(() => Object.keys(focusedFileMap.value).length);
|
||||
|
||||
const languageClass = (path: string) => props.getLanguageClass(path);
|
||||
const formatSize = (size: number) => `${(size / 1024).toFixed(1)}KB`;
|
||||
|
||||
const refreshFocusedFiles = () => {
|
||||
focusStore.fetchFocusedFiles().catch(() => {});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (!props.collapsed) {
|
||||
refreshFocusedFiles();
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.collapsed,
|
||||
collapsed => {
|
||||
if (!collapsed) {
|
||||
refreshFocusedFiles();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<aside class="sidebar left-sidebar" :style="{ width: width + 'px' }">
|
||||
<aside
|
||||
class="sidebar left-sidebar"
|
||||
:class="{ 'panel-hidden': hidden }"
|
||||
:style="panelStyles"
|
||||
:aria-hidden="hidden ? 'true' : 'false'"
|
||||
>
|
||||
<div class="sidebar-status">
|
||||
<div class="compact-status-card">
|
||||
<div class="status-line">
|
||||
@ -11,7 +16,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-indicators">
|
||||
<span class="mode-indicator" :class="{ thinking: thinkingMode, fast: !thinkingMode }">
|
||||
<button
|
||||
type="button"
|
||||
class="mode-indicator"
|
||||
:class="{ thinking: thinkingMode, fast: !thinkingMode }"
|
||||
:title="thinkingMode ? '切换到快速模式' : '切换到思考模式'"
|
||||
:aria-pressed="thinkingMode ? 'true' : 'false'"
|
||||
@click="$emit('toggle-mode')"
|
||||
>
|
||||
<transition name="mode-icon" mode="out-in">
|
||||
<span
|
||||
class="icon icon-sm"
|
||||
@ -20,7 +32,7 @@
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
</transition>
|
||||
</span>
|
||||
</button>
|
||||
<span class="connection-dot" :class="{ active: isConnected }" :title="isConnected ? '已连接' : '未连接'"></span>
|
||||
</div>
|
||||
</div>
|
||||
@ -122,7 +134,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import FileNode from '@/components/files/FileNode.vue';
|
||||
import { useFileStore } from '@/stores/file';
|
||||
@ -138,12 +150,14 @@ const props = defineProps<{
|
||||
isConnected: boolean;
|
||||
panelMenuOpen: boolean;
|
||||
panelMode: 'files' | 'todo' | 'subAgents';
|
||||
hidden?: boolean;
|
||||
}>();
|
||||
|
||||
defineEmits<{
|
||||
(event: 'toggle-panel-menu'): void;
|
||||
(event: 'select-panel', mode: 'files' | 'todo' | 'subAgents'): void;
|
||||
(event: 'open-file-manager'): void;
|
||||
(event: 'toggle-mode'): void;
|
||||
}>();
|
||||
|
||||
const panelMenuWrapper = ref<HTMLElement | null>(null);
|
||||
@ -156,6 +170,15 @@ const openSubAgent = (agent: any) => {
|
||||
subAgentStore.openSubAgent(agent);
|
||||
};
|
||||
|
||||
const panelStyles = computed(() => {
|
||||
const basis = props.hidden ? 0 : props.width;
|
||||
return {
|
||||
width: `${basis}px`,
|
||||
minWidth: `${basis}px`,
|
||||
flexBasis: `${basis}px`
|
||||
};
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
panelMenuWrapper
|
||||
});
|
||||
|
||||
@ -54,6 +54,20 @@
|
||||
</slot>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="collapsed"
|
||||
type="button"
|
||||
class="collapsed-control-btn utility-panel-toggle-btn"
|
||||
:class="{ active: utilityPanelHidden }"
|
||||
:title="utilityPanelHidden ? '显示工作面板' : '隐藏工作面板'"
|
||||
@click="$emit('toggle-utility-panel')"
|
||||
:aria-pressed="utilityPanelHidden ? 'true' : 'false'"
|
||||
>
|
||||
<span class="sr-only">{{ utilityPanelHidden ? '显示' : '隐藏' }}工作面板</span>
|
||||
<span class="layers-icon" aria-hidden="true">
|
||||
<span class="icon icon-md" :style="iconStyle('layers')"></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
@ -153,6 +167,7 @@
|
||||
<script setup lang="ts">
|
||||
defineOptions({ name: 'ConversationSidebar' });
|
||||
|
||||
import { computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useUiStore } from '@/stores/ui';
|
||||
import { useConversationStore } from '@/stores/conversation';
|
||||
@ -161,6 +176,7 @@ import { usePersonalizationStore } from '@/stores/personalization';
|
||||
const props = defineProps<{
|
||||
formatTime?: (input: unknown) => string;
|
||||
iconStyle?: (key: string) => Record<string, string>;
|
||||
utilityPanelHidden?: boolean;
|
||||
}>();
|
||||
|
||||
defineEmits<{
|
||||
@ -172,6 +188,7 @@ defineEmits<{
|
||||
(event: 'personal'): void;
|
||||
(event: 'delete', id: string): void;
|
||||
(event: 'duplicate', id: string): void;
|
||||
(event: 'toggle-utility-panel'): void;
|
||||
}>();
|
||||
|
||||
const uiStore = useUiStore();
|
||||
@ -191,4 +208,5 @@ const { visible: personalPageVisible } = storeToRefs(personalizationStore);
|
||||
|
||||
const formatTime = (value: unknown) => (props.formatTime ? props.formatTime(value) : String(value));
|
||||
const iconStyle = (key: string) => (props.iconStyle ? props.iconStyle(key) : {});
|
||||
const utilityPanelHidden = computed(() => !!props.utilityPanelHidden);
|
||||
</script>
|
||||
|
||||
@ -48,6 +48,7 @@ interface EasterEggState {
|
||||
|
||||
interface UiState {
|
||||
sidebarCollapsed: boolean;
|
||||
utilityPanelHidden: boolean;
|
||||
panelMode: PanelMode;
|
||||
panelMenuOpen: boolean;
|
||||
leftWidth: number;
|
||||
@ -69,6 +70,7 @@ interface UiState {
|
||||
export const useUiStore = defineStore('ui', {
|
||||
state: (): UiState => ({
|
||||
sidebarCollapsed: true,
|
||||
utilityPanelHidden: false,
|
||||
panelMode: 'files',
|
||||
panelMenuOpen: false,
|
||||
leftWidth: 350,
|
||||
@ -98,6 +100,12 @@ export const useUiStore = defineStore('ui', {
|
||||
setSidebarCollapsed(collapsed: boolean) {
|
||||
this.sidebarCollapsed = collapsed;
|
||||
},
|
||||
setUtilityPanelHidden(hidden: boolean) {
|
||||
this.utilityPanelHidden = hidden;
|
||||
},
|
||||
toggleUtilityPanelHidden() {
|
||||
this.utilityPanelHidden = !this.utilityPanelHidden;
|
||||
},
|
||||
toggleSidebar() {
|
||||
this.sidebarCollapsed = !this.sidebarCollapsed;
|
||||
},
|
||||
|
||||
@ -22,6 +22,18 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main-container.utility-panel-hidden .messages-area {
|
||||
max-width: 960px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
padding-left: clamp(24px, 6vw, 72px);
|
||||
padding-right: clamp(24px, 6vw, 72px);
|
||||
}
|
||||
|
||||
.main-container.utility-panel-hidden .message-block {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.chat-container .input-area {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
/* 聚焦文件 */
|
||||
.focused-files {
|
||||
padding: 16px;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
o-files {
|
||||
.no-files {
|
||||
text-align: center;
|
||||
color: var(--claude-text-secondary);
|
||||
padding: 60px 20px;
|
||||
font-size: 14px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
border: 1px dashed var(--claude-border);
|
||||
}
|
||||
|
||||
.file-tabs {
|
||||
@ -17,21 +21,21 @@ o-files {
|
||||
}
|
||||
|
||||
.file-tab {
|
||||
border: 1px solid var(--claude-border);
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(118, 103, 84, 0.15);
|
||||
border-radius: 14px;
|
||||
overflow: hidden;
|
||||
background: rgba(255, 255, 255, 0.75);
|
||||
box-shadow: 0 12px 28px rgba(61, 57, 41, 0.08);
|
||||
background: #fff;
|
||||
box-shadow: 0 10px 24px rgba(61, 57, 41, 0.08);
|
||||
}
|
||||
|
||||
.tab-header {
|
||||
background: rgba(218, 119, 86, 0.08);
|
||||
padding: 10px 16px;
|
||||
background: rgba(247, 244, 240, 0.9);
|
||||
padding: 10px 18px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px solid var(--claude-border);
|
||||
border-bottom: 1px solid rgba(118, 103, 84, 0.12);
|
||||
}
|
||||
|
||||
.file-name {
|
||||
@ -45,19 +49,22 @@ o-files {
|
||||
}
|
||||
|
||||
.file-content {
|
||||
max-height: 320px;
|
||||
max-height: 340px;
|
||||
overflow-y: auto;
|
||||
background: #1e1e1e;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.file-content pre {
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
padding: 16px 20px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.file-content code {
|
||||
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: #aed581;
|
||||
color: #2c2c2c;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
@ -23,6 +23,24 @@
|
||||
.sidebar.left-sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition:
|
||||
width 0.35s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
min-width 0.35s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
flex-basis 0.35s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
transform 0.35s ease,
|
||||
opacity 0.35s ease;
|
||||
}
|
||||
|
||||
.sidebar.left-sidebar.panel-hidden {
|
||||
opacity: 0;
|
||||
transform: translateY(-80px);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.sidebar.left-sidebar.panel-hidden .sidebar-status,
|
||||
.sidebar.left-sidebar.panel-hidden .sidebar-panel-card-wrapper {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.sidebar-status {
|
||||
@ -86,6 +104,8 @@
|
||||
color: #fffef8;
|
||||
box-shadow: 0 8px 20px rgba(189, 93, 58, 0.25);
|
||||
transition: background 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mode-indicator.fast {
|
||||
@ -224,6 +244,7 @@
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.sidebar-panel-card .sidebar-header {
|
||||
|
||||
@ -142,6 +142,34 @@
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.utility-panel-toggle-btn {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 24px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #2f251b;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: color 0.25s ease, transform 0.2s ease;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.utility-panel-toggle-btn .icon {
|
||||
--icon-size: 22px;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.utility-panel-toggle-btn:hover,
|
||||
.utility-panel-toggle-btn:focus-visible {
|
||||
color: var(--claude-accent);
|
||||
}
|
||||
|
||||
.utility-panel-toggle-btn.active {
|
||||
color: #2f251b;
|
||||
}
|
||||
|
||||
.new-conversation-btn {
|
||||
flex: 1;
|
||||
background: linear-gradient(135deg, var(--claude-accent) 0%, var(--claude-accent-strong) 100%);
|
||||
|
||||
@ -9,6 +9,14 @@
|
||||
color: var(--claude-text);
|
||||
}
|
||||
|
||||
.main-container.utility-panel-hidden {
|
||||
background: var(--claude-bg);
|
||||
}
|
||||
|
||||
.main-container.utility-panel-hidden .chat-container {
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
}
|
||||
|
||||
#app {
|
||||
min-height: var(--app-viewport, 100vh);
|
||||
background: var(--claude-bg);
|
||||
|
||||
@ -17,6 +17,7 @@ export const ICONS = Object.freeze({
|
||||
hammer: '/static/icons/hammer.svg',
|
||||
info: '/static/icons/info.svg',
|
||||
laptop: '/static/icons/laptop.svg',
|
||||
layers: '/static/icons/layers.svg',
|
||||
menu: '/static/icons/menu.svg',
|
||||
monitor: '/static/icons/monitor.svg',
|
||||
octagon: '/static/icons/octagon.svg',
|
||||
|
||||
@ -525,7 +525,7 @@ class WebTerminal(MainTerminal):
|
||||
|
||||
|
||||
# 如果是聚焦操作,广播聚焦文件更新
|
||||
if tool_name in ['focus_file', 'unfocus_file', 'modify_file']:
|
||||
if tool_name in ['focus_file', 'unfocus_file', 'modify_file', 'append_to_file']:
|
||||
try:
|
||||
focused_files_dict = self.get_focused_files_info()
|
||||
self.broadcast('focused_files_update', focused_files_dict)
|
||||
|
||||
@ -2757,6 +2757,10 @@ async def handle_task_with_sender(terminal: WebTerminal, message, sender, client
|
||||
if refreshed.get("success"):
|
||||
web_terminal.focused_files[path] = refreshed["content"]
|
||||
debug_log(f"聚焦文件已刷新: {path}")
|
||||
try:
|
||||
sender('focused_files_update', web_terminal.get_focused_files_info())
|
||||
except Exception as focus_exc:
|
||||
debug_log(f"广播聚焦文件更新失败: {focus_exc}")
|
||||
|
||||
debug_log(f"追加写入完成: {summary}")
|
||||
else:
|
||||
@ -3108,6 +3112,10 @@ async def handle_task_with_sender(terminal: WebTerminal, message, sender, client
|
||||
if refreshed.get("success"):
|
||||
web_terminal.focused_files[path] = refreshed["content"]
|
||||
debug_log(f"聚焦文件已刷新: {path}")
|
||||
try:
|
||||
sender('focused_files_update', web_terminal.get_focused_files_info())
|
||||
except Exception as focus_exc:
|
||||
debug_log(f"广播聚焦文件更新失败: {focus_exc}")
|
||||
|
||||
pending_modify = None
|
||||
modify_probe_buffer = ""
|
||||
@ -4093,7 +4101,7 @@ async def handle_task_with_sender(terminal: WebTerminal, message, sender, client
|
||||
sender('update_action', update_payload)
|
||||
|
||||
# 更新UI状态
|
||||
if function_name in ['focus_file', 'unfocus_file', 'modify_file']:
|
||||
if function_name in ['focus_file', 'unfocus_file', 'modify_file', 'append_to_file']:
|
||||
sender('focused_files_update', web_terminal.get_focused_files_info())
|
||||
|
||||
if function_name in ['create_file', 'delete_file', 'rename_file', 'create_folder']:
|
||||
|
||||
@ -2662,6 +2662,10 @@ async def handle_task_with_sender(terminal: WebTerminal, message, sender, client
|
||||
if refreshed.get("success"):
|
||||
web_terminal.focused_files[path] = refreshed["content"]
|
||||
debug_log(f"聚焦文件已刷新: {path}")
|
||||
try:
|
||||
sender('focused_files_update', web_terminal.get_focused_files_info())
|
||||
except Exception as focus_exc:
|
||||
debug_log(f"广播聚焦文件更新失败: {focus_exc}")
|
||||
|
||||
debug_log(f"追加写入完成: {summary}")
|
||||
else:
|
||||
@ -2961,7 +2965,8 @@ async def handle_task_with_sender(terminal: WebTerminal, message, sender, client
|
||||
summary_parts.append(apply_result["error"])
|
||||
|
||||
matching_note = "提示:补丁匹配基于完整文本,包含注释和空白符,请确保 <<<OLD>>> 段落与文件内容逐字一致。如果修改成功,请忽略,如果失败,请明确原文后再次尝试。"
|
||||
summary_parts.append(matching_note)
|
||||
if failed_blocks or not completed_blocks:
|
||||
summary_parts.append(matching_note)
|
||||
summary_message = " ".join(summary_parts).strip()
|
||||
result["summary_message"] = summary_message
|
||||
result["success"] = bool(completed_blocks) and not failed_blocks and apply_result.get("error") is None
|
||||
@ -3013,6 +3018,10 @@ async def handle_task_with_sender(terminal: WebTerminal, message, sender, client
|
||||
if refreshed.get("success"):
|
||||
web_terminal.focused_files[path] = refreshed["content"]
|
||||
debug_log(f"聚焦文件已刷新: {path}")
|
||||
try:
|
||||
sender('focused_files_update', web_terminal.get_focused_files_info())
|
||||
except Exception as focus_exc:
|
||||
debug_log(f"广播聚焦文件更新失败: {focus_exc}")
|
||||
|
||||
pending_modify = None
|
||||
modify_probe_buffer = ""
|
||||
@ -4089,7 +4098,7 @@ async def handle_task_with_sender(terminal: WebTerminal, message, sender, client
|
||||
sender('update_action', update_payload)
|
||||
|
||||
# 更新UI状态
|
||||
if function_name in ['focus_file', 'unfocus_file', 'modify_file']:
|
||||
if function_name in ['focus_file', 'unfocus_file', 'modify_file', 'append_to_file']:
|
||||
sender('focused_files_update', web_terminal.get_focused_files_info())
|
||||
|
||||
if function_name in ['create_file', 'delete_file', 'rename_file', 'create_folder']:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user