Merge pull request #3079 from code-yeongyu/refactor/deslop-cli-mcp-openclaw

refactor(cli,mcp,openclaw): remove AI slop from code comments
This commit is contained in:
YeonGyu-Kim
2026-04-03 21:46:20 +09:00
committed by GitHub
13 changed files with 38 additions and 60 deletions
-1
View File
@@ -103,7 +103,6 @@ export function handleMessagePartUpdated(ctx: RunContext, payload: EventPayload,
if (payload.type !== "message.part.updated") return if (payload.type !== "message.part.updated") return
const props = payload.properties as MessagePartUpdatedProps | undefined const props = payload.properties as MessagePartUpdatedProps | undefined
// Current OpenCode puts sessionID inside part; legacy puts it in info
const partSid = getPartSessionId(props) const partSid = getPartSessionId(props)
const infoSid = getInfoSessionId(props) const infoSid = getInfoSessionId(props)
if ((partSid ?? infoSid) !== ctx.sessionID) return if ((partSid ?? infoSid) !== ctx.sessionID) return
-2
View File
@@ -17,7 +17,6 @@ export interface EventState {
currentModel: string | null currentModel: string | null
/** Current model variant from the latest assistant message */ /** Current model variant from the latest assistant message */
currentVariant: string | null currentVariant: string | null
/** Current message role (user/assistant) — used to filter user messages from display */
currentMessageRole: string | null currentMessageRole: string | null
/** Agent profile colors keyed by display name */ /** Agent profile colors keyed by display name */
agentColorsByName: Record<string, string> agentColorsByName: Record<string, string>
@@ -39,7 +38,6 @@ export interface EventState {
textAtLineStart: boolean textAtLineStart: boolean
/** Whether reasoning stream is currently at line start (for padding) */ /** Whether reasoning stream is currently at line start (for padding) */
thinkingAtLineStart: boolean thinkingAtLineStart: boolean
/** Current assistant message ID — prevents counter resets on repeated message.updated for same message */
currentMessageId: string | null currentMessageId: string | null
/** Assistant message start timestamp by message ID */ /** Assistant message start timestamp by message ID */
messageStartedAtById: Record<string, number> messageStartedAtById: Record<string, number>
-15
View File
@@ -50,7 +50,6 @@ export async function pollForCompletion(
return 130 return 130
} }
// ERROR CHECK FIRST — errors must not be masked by other gates
if (eventState.mainSessionError) { if (eventState.mainSessionError) {
errorCycleCount++ errorCycleCount++
if (errorCycleCount >= ERROR_GRACE_CYCLES) { if (errorCycleCount >= ERROR_GRACE_CYCLES) {
@@ -62,19 +61,15 @@ export async function pollForCompletion(
) )
return 1 return 1
} }
// Continue polling during grace period to allow recovery
continue continue
} else { } else {
// Reset error counter when error clears (recovery succeeded)
errorCycleCount = 0 errorCycleCount = 0
} }
// Watchdog: if no events received for N seconds, verify session status via API
let mainSessionStatus: "idle" | "busy" | "retry" | null = null let mainSessionStatus: "idle" | "busy" | "retry" | null = null
if (eventState.lastEventTimestamp !== null) { if (eventState.lastEventTimestamp !== null) {
const timeSinceLastEvent = Date.now() - eventState.lastEventTimestamp const timeSinceLastEvent = Date.now() - eventState.lastEventTimestamp
if (timeSinceLastEvent > eventWatchdogMs) { if (timeSinceLastEvent > eventWatchdogMs) {
// Events stopped coming - verify actual session state
console.log( console.log(
pc.yellow( pc.yellow(
`\n No events for ${Math.round( `\n No events for ${Math.round(
@@ -83,7 +78,6 @@ export async function pollForCompletion(
) )
) )
// Force check session status directly
mainSessionStatus = await getMainSessionStatus(ctx) mainSessionStatus = await getMainSessionStatus(ctx)
if (mainSessionStatus === "idle") { if (mainSessionStatus === "idle") {
eventState.mainSessionIdle = true eventState.mainSessionIdle = true
@@ -91,12 +85,10 @@ export async function pollForCompletion(
eventState.mainSessionIdle = false eventState.mainSessionIdle = false
} }
// Reset timestamp to avoid repeated checks
eventState.lastEventTimestamp = Date.now() eventState.lastEventTimestamp = Date.now()
} }
} }
// Only call getMainSessionStatus if watchdog didn't already check
if (mainSessionStatus === null) { if (mainSessionStatus === null) {
mainSessionStatus = await getMainSessionStatus(ctx) mainSessionStatus = await getMainSessionStatus(ctx)
} }
@@ -122,15 +114,11 @@ export async function pollForCompletion(
continue continue
} }
// Secondary timeout: if we've been polling for reasonable time but haven't
// received meaningful work via events, check if there's active work via API
// Only check once to avoid unnecessary API calls every poll cycle
if ( if (
Date.now() - pollStartTimestamp > secondaryMeaningfulWorkTimeoutMs && Date.now() - pollStartTimestamp > secondaryMeaningfulWorkTimeoutMs &&
!secondaryTimeoutChecked !secondaryTimeoutChecked
) { ) {
secondaryTimeoutChecked = true secondaryTimeoutChecked = true
// Check if session actually has pending work (children, todos, etc.)
const childrenRes = await ctx.client.session.children({ const childrenRes = await ctx.client.session.children({
path: { id: ctx.sessionID }, path: { id: ctx.sessionID },
query: { directory: ctx.directory }, query: { directory: ctx.directory },
@@ -154,7 +142,6 @@ export async function pollForCompletion(
const hasActiveWork = hasActiveChildren || hasActiveTodos const hasActiveWork = hasActiveChildren || hasActiveTodos
if (hasActiveWork) { if (hasActiveWork) {
// Assume meaningful work is happening even without events
eventState.hasReceivedMeaningfulWork = true eventState.hasReceivedMeaningfulWork = true
console.log( console.log(
pc.yellow( pc.yellow(
@@ -166,12 +153,10 @@ export async function pollForCompletion(
} }
} }
} else { } else {
// Track when first meaningful work was received
if (firstWorkTimestamp === null) { if (firstWorkTimestamp === null) {
firstWorkTimestamp = Date.now() firstWorkTimestamp = Date.now()
} }
// Don't check completion during stabilization period
if (Date.now() - firstWorkTimestamp < minStabilizationMs) { if (Date.now() - firstWorkTimestamp < minStabilizationMs) {
consecutiveCompleteChecks = 0 consecutiveCompleteChecks = 0
continue continue
-1
View File
@@ -114,7 +114,6 @@ export async function run(options: RunOptions): Promise<number> {
}) })
const exitCode = await pollForCompletion(ctx, eventState, abortController) const exitCode = await pollForCompletion(ctx, eventState, abortController)
// Abort the event stream to stop the processor
abortController.abort() abortController.abort()
await waitForEventProcessorShutdown(eventProcessor) await waitForEventProcessorShutdown(eventProcessor)
-1
View File
@@ -27,7 +27,6 @@ export async function resolveSession(options: {
const res = await client.session.create({ const res = await client.session.create({
body: { body: {
title: "oh-my-opencode run", title: "oh-my-opencode run",
// In CLI run mode there's no TUI to answer questions.
permission: [ permission: [
{ permission: "question", action: "deny" as const, pattern: "*" }, { permission: "question", action: "deny" as const, pattern: "*" },
], ],
-1
View File
@@ -81,7 +81,6 @@ export interface MessageUpdatedProps {
} }
export interface MessagePartUpdatedProps { export interface MessagePartUpdatedProps {
/** @deprecated Legacy structure — current OpenCode puts sessionID inside part */
info?: { sessionID?: string; sessionId?: string; role?: string } info?: { sessionID?: string; sessionId?: string; role?: string }
part?: { part?: {
id?: string id?: string
-1
View File
@@ -5,6 +5,5 @@ export const context7 = {
headers: process.env.CONTEXT7_API_KEY headers: process.env.CONTEXT7_API_KEY
? { Authorization: `Bearer ${process.env.CONTEXT7_API_KEY}` } ? { Authorization: `Bearer ${process.env.CONTEXT7_API_KEY}` }
: undefined, : undefined,
// Disable OAuth auto-detection - Context7 uses API key header, not OAuth
oauth: false as const, oauth: false as const,
} }
-2
View File
@@ -30,7 +30,6 @@ export function createWebsearchConfig(config?: WebsearchConfig): RemoteMcpConfig
} }
} }
// Default to Exa
return { return {
type: "remote" as const, type: "remote" as const,
url: process.env.EXA_API_KEY url: process.env.EXA_API_KEY
@@ -42,5 +41,4 @@ export function createWebsearchConfig(config?: WebsearchConfig): RemoteMcpConfig
} }
} }
// Backward compatibility: export static instance using default config
export const websearch = createWebsearchConfig() export const websearch = createWebsearchConfig()
-2
View File
@@ -89,11 +89,9 @@ export function resolveGateway(
return null return null
} }
// Validate based on gateway type
if (gateway.type === "command") { if (gateway.type === "command") {
if (!gateway.command) return null if (!gateway.command) return null
} else { } else {
// HTTP gateway
if (!gateway.url) return null if (!gateway.url) return null
} }
-1
View File
@@ -134,7 +134,6 @@ export async function wakeCommandGateway(
try { try {
const timeout = resolveCommandTimeoutMs(gatewayConfig.timeout) const timeout = resolveCommandTimeoutMs(gatewayConfig.timeout)
// Interpolate variables with shell escaping
const interpolated = gatewayConfig.command.replace(/\{\{(\w+)\}\}/g, (_match, key) => { const interpolated = gatewayConfig.command.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
const value = variables[key] const value = variables[key]
if (value === undefined) return _match if (value === undefined) return _match
+36 -20
View File
@@ -82,7 +82,6 @@ function writeSecureFile(filePath: string, content: string): void {
try { try {
chmodSync(filePath, SECURE_FILE_MODE) chmodSync(filePath, SECURE_FILE_MODE)
} catch { } catch {
// Ignore
} }
} }
@@ -98,7 +97,6 @@ function rotateLogIfNeeded(logPath: string): void {
renameSync(logPath, backupPath) renameSync(logPath, backupPath)
} }
} catch { } catch {
// Ignore
} }
} }
@@ -110,7 +108,6 @@ function log(message: string): void {
const logLine = `[${timestamp}] ${message}\n` const logLine = `[${timestamp}] ${message}\n`
appendFileSync(LOG_FILE_PATH, logLine, { mode: SECURE_FILE_MODE }) appendFileSync(LOG_FILE_PATH, logLine, { mode: SECURE_FILE_MODE })
} catch { } catch {
// Ignore
} }
} }
@@ -130,6 +127,31 @@ interface DaemonState {
lastError?: string lastError?: string
} }
interface TelegramMessage {
message_id?: number
chat?: { id?: number | string }
text?: string
reply_to_message?: { message_id?: number }
}
interface TelegramUpdate {
update_id?: number
message?: TelegramMessage
}
interface TelegramUpdatesResponse {
result?: TelegramUpdate[]
}
function parseTelegramUpdatesResponse(body: unknown): TelegramUpdate[] {
if (typeof body !== "object" || body === null) {
return []
}
const result = (body as TelegramUpdatesResponse).result
return Array.isArray(result) ? result : []
}
function readDaemonState(): DaemonState | null { function readDaemonState(): DaemonState | null {
try { try {
if (!existsSync(STATE_FILE_PATH)) return null if (!existsSync(STATE_FILE_PATH)) return null
@@ -195,7 +217,6 @@ export async function isReplyListenerProcess(pid: number): Promise<boolean> {
const cmdline = readFileSync(`/proc/${pid}/cmdline`, "utf-8") const cmdline = readFileSync(`/proc/${pid}/cmdline`, "utf-8")
return cmdline.includes(DAEMON_IDENTITY_MARKER) return cmdline.includes(DAEMON_IDENTITY_MARKER)
} }
// macOS
const proc = spawn(["ps", "-p", String(pid), "-o", "args="], { const proc = spawn(["ps", "-p", String(pid), "-o", "args="], {
stdout: "pipe", stdout: "pipe",
stderr: "ignore", stderr: "ignore",
@@ -222,7 +243,6 @@ export async function isDaemonRunning(): Promise<boolean> {
return true return true
} }
// Input Sanitization
export function sanitizeReplyInput(text: string): string { export function sanitizeReplyInput(text: string): string {
return text return text
.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "") .replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "")
@@ -387,7 +407,6 @@ async function pollDiscord(
}, },
) )
} catch { } catch {
// Ignore
} }
} else { } else {
state.errors++ state.errors++
@@ -427,52 +446,52 @@ async function pollTelegram(
return return
} }
const body = await response.json() as any const body = await response.json()
const updates = body.result || [] const updates = parseTelegramUpdatesResponse(body)
for (const update of updates) { for (const update of updates) {
const msg = update.message const msg = update.message
if (!msg) { if (!msg) {
state.telegramLastUpdateId = update.update_id state.telegramLastUpdateId = update.update_id ?? state.telegramLastUpdateId
writeDaemonState(state) writeDaemonState(state)
continue continue
} }
if (!msg.reply_to_message?.message_id) { if (msg.reply_to_message?.message_id === undefined) {
state.telegramLastUpdateId = update.update_id state.telegramLastUpdateId = update.update_id ?? state.telegramLastUpdateId
writeDaemonState(state) writeDaemonState(state)
continue continue
} }
if (String(msg.chat.id) !== replyListener.telegramChatId) { if (String(msg.chat?.id) !== replyListener.telegramChatId) {
state.telegramLastUpdateId = update.update_id state.telegramLastUpdateId = update.update_id ?? state.telegramLastUpdateId
writeDaemonState(state) writeDaemonState(state)
continue continue
} }
const mapping = lookupByMessageId("telegram", String(msg.reply_to_message.message_id)) const mapping = lookupByMessageId("telegram", String(msg.reply_to_message.message_id))
if (!mapping) { if (!mapping) {
state.telegramLastUpdateId = update.update_id state.telegramLastUpdateId = update.update_id ?? state.telegramLastUpdateId
writeDaemonState(state) writeDaemonState(state)
continue continue
} }
const text = msg.text || "" const text = msg.text || ""
if (!text) { if (!text) {
state.telegramLastUpdateId = update.update_id state.telegramLastUpdateId = update.update_id ?? state.telegramLastUpdateId
writeDaemonState(state) writeDaemonState(state)
continue continue
} }
if (!rateLimiter.canProceed()) { if (!rateLimiter.canProceed()) {
log(`WARN: Rate limit exceeded, dropping Telegram message ${msg.message_id}`) log(`WARN: Rate limit exceeded, dropping Telegram message ${msg.message_id}`)
state.telegramLastUpdateId = update.update_id state.telegramLastUpdateId = update.update_id ?? state.telegramLastUpdateId
writeDaemonState(state) writeDaemonState(state)
state.errors++ state.errors++
continue continue
} }
state.telegramLastUpdateId = update.update_id state.telegramLastUpdateId = update.update_id ?? state.telegramLastUpdateId
writeDaemonState(state) writeDaemonState(state)
const success = await injectReply(mapping.tmuxPaneId, text, "telegram", config) const success = await injectReply(mapping.tmuxPaneId, text, "telegram", config)
@@ -604,9 +623,6 @@ export async function startReplyListener(config: OpenClawConfig): Promise<{ succ
const normalizedConfig = normalizeReplyListenerConfig(config) const normalizedConfig = normalizeReplyListenerConfig(config)
const replyListener = normalizedConfig.replyListener const replyListener = normalizedConfig.replyListener
if (!replyListener?.discordBotToken && !replyListener?.telegramBotToken) { if (!replyListener?.discordBotToken && !replyListener?.telegramBotToken) {
// Only warn if no platforms enabled, but user might just want outbound
// Actually, instructions say: "Fire-and-forget for outbound, daemon process for inbound"
// So if no inbound config, we shouldn't start daemon.
return { return {
success: false, success: false,
message: "No enabled reply listener platforms configured (missing bot tokens/channels)", message: "No enabled reply listener platforms configured (missing bot tokens/channels)",
+1 -10
View File
@@ -44,7 +44,6 @@ function ensureRegistryDir(): void {
} }
function sleepMs(ms: number): void { function sleepMs(ms: number): void {
// Use Atomics.wait for synchronous sleep
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms) Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms)
} }
@@ -79,7 +78,6 @@ function readLockSnapshot(): LockSnapshot | null {
typeof parsed.token === "string" && parsed.token.length > 0 ? parsed.token : null typeof parsed.token === "string" && parsed.token.length > 0 ? parsed.token : null
return { raw, pid, token } return { raw, pid, token }
} catch { } catch {
// Legacy format or plain PID
const [pidStr] = trimmed.split(":") const [pidStr] = trimmed.split(":")
const parsedPid = Number.parseInt(pidStr ?? "", 10) const parsedPid = Number.parseInt(pidStr ?? "", 10)
return { return {
@@ -132,12 +130,10 @@ function acquireRegistryLock(): LockHandle | null {
try { try {
closeSync(fd) closeSync(fd)
} catch { } catch {
// Ignore
} }
try { try {
unlinkSync(REGISTRY_LOCK_PATH) unlinkSync(REGISTRY_LOCK_PATH)
} catch { } catch {
// Ignore
} }
throw writeError throw writeError
} }
@@ -164,7 +160,6 @@ function acquireRegistryLock(): LockHandle | null {
} }
} }
} catch { } catch {
// Ignore errors
} }
sleepMs(LOCK_RETRY_MS) sleepMs(LOCK_RETRY_MS)
} }
@@ -188,8 +183,7 @@ function releaseRegistryLock(lock: LockHandle): void {
try { try {
closeSync(lock.fd) closeSync(lock.fd)
} catch { } catch {
// Ignore }
}
const snapshot = readLockSnapshot() const snapshot = readLockSnapshot()
if (!snapshot || snapshot.token !== lock.token) return if (!snapshot || snapshot.token !== lock.token) return
removeLockIfUnchanged(snapshot) removeLockIfUnchanged(snapshot)
@@ -298,7 +292,6 @@ export function removeSession(sessionId: string): void {
rewriteRegistryUnsafe(filtered) rewriteRegistryUnsafe(filtered)
}, },
() => { () => {
// Best-effort
}, },
) )
} }
@@ -312,7 +305,6 @@ export function removeMessagesByPane(paneId: string): void {
rewriteRegistryUnsafe(filtered) rewriteRegistryUnsafe(filtered)
}, },
() => { () => {
// Best-effort
}, },
) )
} }
@@ -334,7 +326,6 @@ export function pruneStale(): void {
rewriteRegistryUnsafe(filtered) rewriteRegistryUnsafe(filtered)
}, },
() => { () => {
// Best-effort
}, },
) )
} }
+1 -3
View File
@@ -4,8 +4,7 @@ export function getCurrentTmuxSession(): string | null {
const env = process.env.TMUX const env = process.env.TMUX
if (!env) return null if (!env) return null
const match = env.match(/(\d+)$/) const match = env.match(/(\d+)$/)
return match ? `session-${match[1]}` : null // Wait, TMUX env is /tmp/tmux-501/default,1234,0 return match ? `session-${match[1]}` : null
// Reference tmux.js gets session name via `tmux display-message -p '#S'`
} }
export async function getTmuxSessionName(): Promise<string | null> { export async function getTmuxSessionName(): Promise<string | null> {
@@ -17,7 +16,6 @@ export async function getTmuxSessionName(): Promise<string | null> {
const outputPromise = new Response(proc.stdout).text() const outputPromise = new Response(proc.stdout).text()
await proc.exited await proc.exited
const output = await outputPromise const output = await outputPromise
// Await proc.exited ensures exitCode is set; avoid race condition
if (proc.exitCode !== 0) return null if (proc.exitCode !== 0) return null
return output.trim() || null return output.trim() || null
} catch { } catch {