mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +00:00
feat(remote-control): 优化 Web 展示、状态同步与桥接控制流程 (#288)
Co-authored-by: chengzifeng <chengzifeng@meituan.com>
This commit is contained in:
@@ -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 ─────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user