Compare commits

..

No commits in common. "f6cbe78d68de3409cba5b37a2e443aacbe1fd3d6" and "297a6cc5ec0eba7e91abcb7f67ba0898d63152b3" have entirely different histories.

17 changed files with 16 additions and 149 deletions

View File

@ -207,9 +207,7 @@
### 前端调试日志
- **统一筛选词(强制)**:所有临时 `console.log` 必须使用**同一个**筛选前缀(例如 `[route-debug]`),方便用户在浏览器控制台用该前缀一次性筛选。
- **同一次调试任务中严禁使用多个前缀**。如果涉及多个模块如状态栏、Git 摘要、用户问题),应共用同一个前缀(如 `[status-bar-debug]`),通过日志对象里的字段区分模块,而不是发明多个前缀增加用户筛选成本。
- 选择前缀时优先与本次排查的「用户可见现象」对齐,而不是与内部模块名对齐。
- **统一筛选词**:所有临时 `console.log` 必须使用**同一个**筛选前缀(例如 `[route-debug]`),方便用户在浏览器控制台用该前缀一次性筛选。
- **控制数量与时机**
- 禁止一次性输出上百上千条日志刷屏。
- 只在关键路径(入口、分支判断、状态变化、导航动作)打印,避免在循环、高频事件、每帧渲染中输出。

View File

@ -1,6 +1,5 @@
from __future__ import annotations
import json
import re
from typing import Any, Dict, List, Optional
@ -11,16 +10,7 @@ def extract_intent_from_partial(arg_str: str) -> Optional[str]:
return None
match = re.search(r'"intent"\s*:\s*"([^"]{0,128})', arg_str, re.IGNORECASE | re.DOTALL)
if match:
raw = match.group(1)
try:
# 某些模型会对非 ASCII 字符输出 JSON Unicode 转义(如 \u4e2d\u6587
# 这里用 json.loads 安全解码,失败时回退原始值。
decoded = json.loads('"{}"'.format(raw))
if isinstance(decoded, str):
return decoded
except Exception:
pass
return raw
return match.group(1)
return None

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1,35 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -4 200 200" aria-hidden="true">
<style>
.sa-frame, .sa-eye {
stroke: #000000;
stroke-linecap: round;
stroke-linejoin: round;
fill: none;
}
.sa-frame {
stroke-width: 12;
}
.sa-eye {
stroke-width: 10;
}
@media (prefers-color-scheme: dark) {
.sa-frame, .sa-eye {
stroke: #ffffff;
}
}
</style>
<path
class="sa-frame"
d="M 175.959,107.000 Q 180.000,100.000 175.959,93.000 L 144.041,37.718 Q 140.000,30.718 131.917,30.718 L 68.083,30.718 Q 60.000,30.718 55.959,37.718 L 24.041,93.000 Q 20.000,100.000 24.041,107.000 L 55.959,162.282 Q 60.000,169.282 68.083,169.282 L 131.917,169.282 Q 140.000,169.282 144.041,162.282 Z"
/>
<path
class="sa-eye"
d="M 0,-11 Q 0,-5.5 0,0 Q 0,5.5 0,11 Q 0,5.5 0,0 Q 0,-5.5 0,-11"
transform="translate(84, 96)"
/>
<path
class="sa-eye"
d="M 0,-11 Q 0,-5.5 0,0 Q 0,5.5 0,11 Q 0,5.5 0,0 Q 0,-5.5 0,-11"
transform="translate(116, 96)"
/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 B

View File

@ -4,10 +4,6 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Astrion</title>
<link rel="icon" type="image/svg+xml" href="/static/astrion-avatar.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon-16x16.png">
<link rel="apple-touch-icon" sizes="180x180" href="/static/apple-touch-icon.png">
<link rel="stylesheet" href="/static/style.css">
<link rel="stylesheet" href="/static/easter-eggs/flood.css">
<link rel="stylesheet" href="/static/easter-eggs/snake.css">

View File

@ -41,6 +41,7 @@ export async function mounted() {
// 立即加载初始数据(并行获取状态,优先同步运行模式)
const initialDataPromise = this.loadInitialData();
this.refreshProjectGitSummary?.();
this.startProjectGitSummaryIdleRefresh?.();
this.startConnectionHeartbeat();
this.fetchTerminalCount();
@ -49,8 +50,6 @@ export async function mounted() {
if (initialDataPromise && typeof initialDataPromise.then === 'function') {
initialDataPromise
.then(() => {
// 初始数据加载完成后再刷新 git 摘要,确保 workspace/project_path 已就绪
this.refreshProjectGitSummary?.();
// 避免在初始加载阶段被覆盖,加载完成后再兜底检查一次
this.checkTutorialPrompt();
})

View File

@ -232,8 +232,6 @@ export const loadMethods = {
this.fetchNetworkPermission();
await this.fetchVersioningStatus(conversationId, { silent: true });
this.fetchPendingToolApprovals();
this.fetchPendingUserQuestions();
this.refreshProjectGitSummary();
this.fetchConversationTokenStatistics();
this.updateCurrentContextTokens();
traceLog('loadConversation:after-history', {

View File

@ -58,35 +58,6 @@ export const dialogMethods = {
this.userQuestionDialogVisible = true;
this.userQuestionMinimized = false;
},
async fetchPendingUserQuestions() {
if (!this.currentConversationId) {
this.pendingUserQuestions = [];
return;
}
try {
const response = await fetch(
`/api/user-questions/pending?conversation_id=${encodeURIComponent(this.currentConversationId)}`
);
const payload = await response.json().catch(() => ({}));
if (!response.ok || !payload?.success) {
return;
}
const items = Array.isArray(payload.items) ? payload.items : [];
this.pendingUserQuestions = items;
if (items.length > 0) {
this.userQuestionActiveIndex = Math.min(
Math.max(0, Number(this.userQuestionActiveIndex || 0)),
Math.max(0, items.length - 1)
);
} else {
this.userQuestionDialogVisible = false;
this.userQuestionMinimized = false;
this.userQuestionActiveIndex = 0;
}
} catch (_error) {
// ignore
}
},
approveToolApproval(approvalId) {
return this.decideToolApproval(approvalId, 'approved');
},

View File

@ -70,7 +70,7 @@ export const gitMethods = {
if (this.gitChangesPanelOpen) {
this.loadGitChangesDiff?.();
}
} catch (_error) {
} catch (_) {
this.projectGitSummary = null;
this.gitChangesDiff = null;
} finally {

View File

@ -151,9 +151,6 @@ export const routeMethods = {
this.initialRouteResolved = true;
}
await this.restoreComposerDraftState('bootstrap-route:conversation');
if (this.currentConversationId) {
this.fetchPendingUserQuestions?.();
}
},
handlePopState(event) {
const state = event.state || {};

View File

@ -372,7 +372,6 @@ export const socketMethods = {
this.fetchConversationTokenStatistics();
this.updateCurrentContextTokens();
await this.fetchVersioningStatus(this.currentConversationId, { silent: true });
this.fetchPendingUserQuestions();
} catch (e) {
console.warn('获取当前对话标题失败:', e);
this.titleReady = true;

View File

@ -170,7 +170,7 @@
>目标模式就绪</span
>
<button
v-if="pendingUserQuestionCount > 0"
v-if="userQuestionMinimized && pendingUserQuestionCount > 0"
type="button"
class="floating-project-status__notice floating-project-status__notice--button"
@click.stop="$emit('restore-user-question')"
@ -828,43 +828,33 @@ const runtimeQueuedMessagesForRender = computed(() => {
});
const projectGitSummaryForRender = computed(() => {
if (personalizationStore?.form?.show_git_status_bar === false) {
return null;
}
if (personalizationStore?.form?.show_git_status_bar === false) return null;
const summary = props.projectGitSummary;
if (!summary?.has_git) {
return null;
}
if (!summary?.has_git) return null;
const projectName = String(summary.project_name || '').trim();
const branch = String(summary.branch || '').trim();
if (!projectName || !branch) {
return null;
}
const result = {
if (!projectName || !branch) return null;
return {
projectName,
projectPath: String(summary.project_path || '').trim(),
branch,
additions: Math.max(0, Number(summary.additions || 0)),
deletions: Math.max(0, Number(summary.deletions || 0))
};
return result;
});
const floatingStatusVisible = computed(() => {
if (skillSlashMenuOpen.value || fileAtOpen.value || props.quickMenuOpen) {
return false;
}
if (skillSlashMenuOpen.value || fileAtOpen.value || props.quickMenuOpen) return false;
// /git /
if (runtimeQueuedMessagesForRender.value.length > 0 || props.hasPendingRuntimeGuidance) {
if (runtimeQueuedMessagesForRender.value.length > 0 || props.hasPendingRuntimeGuidance)
return false;
}
const visible =
return (
!!projectGitSummaryForRender.value ||
!!props.goalRunning ||
!!props.goalModeArmed ||
(Number(props.pendingUserQuestionCount || 0) > 0) ||
(Number(props.activeSubAgentCount || 0) > 0);
return visible;
(!!props.userQuestionMinimized && Number(props.pendingUserQuestionCount || 0) > 0) ||
(Number(props.activeSubAgentCount || 0) > 0)
);
});
const showComposerAvatar = computed(() => {

View File

@ -213,7 +213,6 @@ function submit() {
gap: 12px;
align-items: center;
padding: 20px 22px 0;
flex-shrink: 0;
}
.user-question-kicker-row {
@ -241,9 +240,6 @@ function submit() {
line-height: 1.55;
font-weight: 650;
letter-spacing: -0.01em;
white-space: pre-wrap;
max-height: min(180px, 30vh);
overflow-y: auto;
}
.user-question-nav {
@ -301,9 +297,6 @@ function submit() {
color: var(--claude-text-secondary);
line-height: 1.6;
font-size: 13px;
white-space: pre-wrap;
max-height: min(160px, 25vh);
overflow-y: auto;
}
.user-question-options {
@ -342,7 +335,6 @@ function submit() {
color: var(--claude-text-secondary);
font-size: 12px;
line-height: 1.42;
white-space: pre-wrap;
}
.user-question-textarea-wrap {

View File

@ -2289,37 +2289,13 @@ const updateFloatingMenuPosition = async () => {
const button = document.querySelector<HTMLElement>(
'.settings-select-wrap.open .settings-select-button'
);
const menu = document.querySelector<HTMLElement>(
'.settings-select-wrap.open .settings-floating-menu'
);
if (!button) {
return;
}
const rect = button.getBoundingClientRect();
const menuWidth = Math.min(300, Math.max(240, window.innerWidth - 32));
const left = Math.max(16, Math.min(rect.right - menuWidth, window.innerWidth - menuWidth - 16));
const padding = 16;
const gap = 10;
const menuHeight = menu?.getBoundingClientRect().height || 0;
let top: number;
if (menuHeight > 0) {
const spaceBelow = window.innerHeight - rect.bottom - padding;
const spaceAbove = rect.top - padding;
if (spaceBelow >= menuHeight) {
top = rect.bottom + gap;
} else if (spaceAbove >= menuHeight) {
top = rect.top - menuHeight - gap;
} else if (spaceBelow >= spaceAbove) {
// max-height
top = Math.max(rect.bottom + gap, window.innerHeight - menuHeight - padding);
} else {
//
top = padding;
}
} else {
top = Math.max(padding, Math.min(rect.bottom + gap, window.innerHeight - 80));
}
const top = Math.max(16, Math.min(rect.bottom + 10, window.innerHeight - 80));
floatingMenuStyle.value = {
position: 'fixed',
top: `${Math.round(top)}px`,

View File

@ -40,10 +40,6 @@ class ServerRefactorSmokeTest(unittest.TestCase):
import server.chat_flow_runner_helpers as helpers
self.assertEqual(helpers.extract_intent_from_partial('{"intent": "fix"}'), "fix")
self.assertEqual(
helpers.extract_intent_from_partial('{"intent": "\\u7b49\\u5f85\\u4e0b\\u8f7d\\u5b8c\\u6210"}'),
"等待下载完成",
)
self.assertEqual(helpers.resolve_monitor_path({"file_path": " a.txt "}), "a.txt")
self.assertEqual(helpers.resolve_monitor_memory([1, 2, 3], entry_limit=2), ["1", "2"])