feat(remote-control): 优化 Web 展示、状态同步与桥接控制流程 (#288)

Co-authored-by: chengzifeng <chengzifeng@meituan.com>
This commit is contained in:
Cheng Zi Feng
2026-04-17 16:21:27 +08:00
committed by GitHub
parent b5c299f5d2
commit 72a2093cd6
64 changed files with 4138 additions and 312 deletions

View File

@@ -28,6 +28,18 @@ import { errorMessage } from '../utils/errors.js'
import type { PermissionMode } from '../utils/permissions/PermissionMode.js'
import { jsonParse } from '../utils/slowOperations.js'
import type { ReplBridgeTransport } from './replBridgeTransport.js'
import {
BASH_INPUT_TAG,
CHANNEL_MESSAGE_TAG,
CROSS_SESSION_MESSAGE_TAG,
LOCAL_COMMAND_CAVEAT_TAG,
REMOTE_REVIEW_PROGRESS_TAG,
REMOTE_REVIEW_TAG,
TASK_NOTIFICATION_TAG,
TEAMMATE_MESSAGE_TAG,
TICK_TAG,
ULTRAPLAN_TAG,
} from '../constants/xml.js'
// ─── Type guards ─────────────────────────────────────────────────────────────
@@ -122,6 +134,85 @@ export function extractTitleText(m: Message): string | undefined {
return clean || undefined
}
const SYSTEM_REMINDER_TAG = 'system-reminder'
const XML_BLOCK_PATTERN =
/\s*<([a-z][\w-]*)(?:\s[^>]*)?>[\s\S]*?<\/\1>\s*/gy
const RUNNING_STATE_META_TAGS = new Set([
BASH_INPUT_TAG,
CHANNEL_MESSAGE_TAG,
CROSS_SESSION_MESSAGE_TAG,
REMOTE_REVIEW_PROGRESS_TAG,
REMOTE_REVIEW_TAG,
TASK_NOTIFICATION_TAG,
TEAMMATE_MESSAGE_TAG,
TICK_TAG,
ULTRAPLAN_TAG,
])
function extractUserMessageText(message: Message): string {
const content = message.message?.content
if (typeof content === 'string') return content
if (!Array.isArray(content)) return ''
return content
.filter(
(
block,
): block is {
type: 'text'
text: string
} =>
!!block &&
typeof block === 'object' &&
block.type === 'text' &&
typeof block.text === 'string',
)
.map(block => block.text)
.join('')
}
function getEnvelopeTagNames(text: string): string[] | null {
const trimmed = text.trim()
if (!trimmed) return null
XML_BLOCK_PATTERN.lastIndex = 0
const tags: string[] = []
while (XML_BLOCK_PATTERN.lastIndex < trimmed.length) {
const match = XML_BLOCK_PATTERN.exec(trimmed)
if (!match) return null
tags.push(match[1]!)
}
return tags.length > 0 ? tags : null
}
/**
* Remote Control uses user messages to infer "a turn is actively running" in
* places where the server does not derive that state for us. Hidden local
* slash-command scaffolding (for example `<local-command-caveat>` and pure
* `<system-reminder>` wrappers from `/proactive`) should not flip the session
* back to running after the command has already completed.
*/
export function shouldReportRunningForMessage(message: Message): boolean {
if (message.type !== 'user') return false
if (message.isVisibleInTranscriptOnly) return false
if (message.toolUseResult !== undefined) return true
if (!message.isMeta) return true
const tags = getEnvelopeTagNames(extractUserMessageText(message))
if (!tags) return true
return tags.some(
tag =>
tag !== LOCAL_COMMAND_CAVEAT_TAG &&
tag !== SYSTEM_REMINDER_TAG &&
RUNNING_STATE_META_TAGS.has(tag),
)
}
export function shouldReportRunningForMessages(
messages: readonly Message[],
): boolean {
return messages.some(shouldReportRunningForMessage)
}
// ─── Ingress routing ─────────────────────────────────────────────────────────
/**