{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "agent-coding", "title": "Agent Coding", "description": "Agent Work with an injected bounded command executor, approval-required write and bash tools, poisoned runtime isolation, and a controlled plain-text terminal", "dependencies": ["@wener/common@^3.0.0", "ai@7.0.31", "daisyui", "lucide-react", "zod@4.4.3"], "registryDependencies": ["https://ui-components.wener.me/r/agent-work.json"], "files": [ { "path": "registry/default/blocks/agent-coding/command-types.ts", "content": "export type AgentCommandRequest = {\n\tcommand: string;\n\tstdin?: string;\n};\n\nexport type AgentTerminalResult = {\n\taborted?: boolean;\n\tdurationMs: number;\n\texitCode: number;\n\tmutationMayContinue?: boolean;\n\tpoisoned?: boolean;\n\tsettled: boolean;\n\tstderr: string;\n\tstdout: string;\n\ttimedOut?: boolean;\n\ttruncated: boolean;\n\tworkspaceChanged?: boolean;\n};\n\nexport type AgentCommandExecutor = {\n\texecute(request: AgentCommandRequest, options?: { signal?: AbortSignal }): Promise;\n};\n\nexport type AgentTerminalEntry = {\n\tcommand: string;\n\tfinishedAt?: number;\n\tid: string;\n\tresult?: AgentTerminalResult;\n\tstartedAt: number;\n\tstatus: 'cancelled' | 'failed' | 'running' | 'succeeded';\n};\n\nexport type AgentActiveCommand = Pick;\n\nexport type AgentCommandRuntimeState = {\n\tmutationMayContinue: boolean;\n\tpoisoned: boolean;\n\trunning: boolean;\n};\n", "type": "registry:lib", "target": "@components/blocks/agent-coding/command-types.ts" }, { "path": "registry/default/blocks/agent-coding/command-runtime.ts", "content": "import type {\n\tAgentCommandExecutor,\n\tAgentCommandRequest,\n\tAgentCommandRuntimeState,\n\tAgentTerminalResult,\n} from './command-types';\n\nexport const MaxAgentCommandBytes = 16 * 1024;\nexport const MaxAgentCommandStdinBytes = 256 * 1024;\nexport const MaxAgentCommandOutputBytes = 256 * 1024;\nexport const DefaultAgentCommandCancelSettleGraceMs = 1_000;\n\nexport type AgentCommandRuntime = {\n\tcancelCurrent(reason?: unknown): void;\n\tcancelCurrentAndWait(reason?: unknown): Promise;\n\texecute(\n\t\trequest: AgentCommandRequest,\n\t\toptions?: { onAcquired?: () => void; signal?: AbortSignal },\n\t): Promise;\n\tgetState(): AgentCommandRuntimeState;\n};\n\nexport type AgentCommandRuntimeOptions = {\n\tcancelSettleGraceMs?: number;\n};\n\ntype ExecutorOutcome = { error: unknown; kind: 'error' } | { kind: 'result'; result: AgentTerminalResult };\ntype CancellationOutcome = { kind: 'cancelled' };\ntype GraceExpiredOutcome = { kind: 'grace-expired' };\n\nexport function createAgentCommandRuntime(\n\texecutor: AgentCommandExecutor,\n\toptions: AgentCommandRuntimeOptions = {},\n): AgentCommandRuntime {\n\tconst cancelSettleGraceMs = resolveCancelSettleGrace(options.cancelSettleGraceMs);\n\tlet running = false;\n\tlet poisoned = false;\n\tlet mutationMayContinue = false;\n\tlet activeController: AbortController | undefined;\n\tlet activeCompletion: Promise | undefined;\n\treturn {\n\t\tcancelCurrent(reason = 'cancelled') {\n\t\t\tactiveController?.abort(reason);\n\t\t},\n\t\tasync cancelCurrentAndWait(reason = 'cancelled') {\n\t\t\tactiveController?.abort(reason);\n\t\t\tawait activeCompletion;\n\t\t\treturn { mutationMayContinue, poisoned, running };\n\t\t},\n\t\tasync execute(request, executeOptions) {\n\t\t\tif (poisoned) return limitedResult('执行器已被未完成的命令污染,请替换执行器后重试。', 125, true);\n\t\t\tif (running) return limitedResult('已有命令正在执行。', 125, false);\n\t\t\tif (utf8Bytes(request.command) > MaxAgentCommandBytes) {\n\t\t\t\treturn limitedResult(`命令超过 ${MaxAgentCommandBytes} 字节限制。`, 126, false);\n\t\t\t}\n\t\t\tif (utf8Bytes(request.stdin ?? '') > MaxAgentCommandStdinBytes) {\n\t\t\t\treturn limitedResult(`标准输入超过 ${MaxAgentCommandStdinBytes} 字节限制。`, 126, false);\n\t\t\t}\n\t\t\trunning = true;\n\t\t\tlet finishCompletion!: () => void;\n\t\t\tconst completion = new Promise((resolve) => {\n\t\t\t\tfinishCompletion = resolve;\n\t\t\t});\n\t\t\tactiveCompletion = completion;\n\t\t\tconst startedAt = now();\n\t\t\tconst controller = new AbortController();\n\t\t\tactiveController = controller;\n\t\t\tconst onExternalAbort = () => controller.abort(executeOptions?.signal?.reason);\n\t\t\texecuteOptions?.signal?.addEventListener('abort', onExternalAbort, { once: true });\n\t\t\tif (executeOptions?.signal?.aborted) onExternalAbort();\n\t\t\tlet notifyCancelled: (() => void) | undefined;\n\t\t\tconst cancellation = new Promise((resolve) => {\n\t\t\t\tnotifyCancelled = () => resolve({ kind: 'cancelled' });\n\t\t\t});\n\t\t\tconst onRuntimeAbort = () => notifyCancelled?.();\n\t\t\tcontroller.signal.addEventListener('abort', onRuntimeAbort, { once: true });\n\t\t\tif (controller.signal.aborted) onRuntimeAbort();\n\t\t\ttry {\n\t\t\t\texecuteOptions?.onAcquired?.();\n\t\t\t\tlet delegated: Promise;\n\t\t\t\ttry {\n\t\t\t\t\tdelegated = executor.execute(\n\t\t\t\t\t\t{ command: request.command, stdin: request.stdin },\n\t\t\t\t\t\t{ signal: controller.signal },\n\t\t\t\t\t);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tdelegated = Promise.reject(error);\n\t\t\t\t}\n\t\t\t\tconst executorOutcome: Promise = delegated.then(\n\t\t\t\t\t(result) => ({ kind: 'result', result }),\n\t\t\t\t\t(error: unknown) => ({ error, kind: 'error' }),\n\t\t\t\t);\n\t\t\t\tconst first = await Promise.race([executorOutcome, cancellation]);\n\t\t\t\tconst outcome =\n\t\t\t\t\tfirst.kind === 'cancelled'\n\t\t\t\t\t\t? await settleWithinCancellationGrace(executorOutcome, cancelSettleGraceMs)\n\t\t\t\t\t\t: first;\n\t\t\t\tif (outcome.kind === 'grace-expired') {\n\t\t\t\t\tpoisoned = true;\n\t\t\t\t\tmutationMayContinue = true;\n\t\t\t\t\treturn cancellationDidNotSettleResult(startedAt, cancelSettleGraceMs);\n\t\t\t\t}\n\t\t\t\tif (outcome.kind === 'error') {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdurationMs: Math.max(0, now() - startedAt),\n\t\t\t\t\t\texitCode: 1,\n\t\t\t\t\t\tsettled: true,\n\t\t\t\t\t\tstderr: toErrorMessage(outcome.error).slice(0, 1024),\n\t\t\t\t\t\tstdout: '',\n\t\t\t\t\t\ttruncated: false,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst output = boundOutput(outcome.result.stdout, outcome.result.stderr, MaxAgentCommandOutputBytes);\n\t\t\t\tconst result: AgentTerminalResult = {\n\t\t\t\t\t...outcome.result,\n\t\t\t\t\tdurationMs: safeDuration(outcome.result.durationMs, startedAt),\n\t\t\t\t\tsettled: outcome.result.settled === true,\n\t\t\t\t\tstderr: output.stderr,\n\t\t\t\t\tstdout: output.stdout,\n\t\t\t\t\ttruncated: outcome.result.truncated || output.truncated,\n\t\t\t\t};\n\t\t\t\tif (!result.settled || result.mutationMayContinue) mutationMayContinue = true;\n\t\t\t\tif (!result.settled || result.mutationMayContinue || result.poisoned) poisoned = true;\n\t\t\t\treturn { ...result, poisoned: poisoned || result.poisoned };\n\t\t\t} finally {\n\t\t\t\texecuteOptions?.signal?.removeEventListener('abort', onExternalAbort);\n\t\t\t\tcontroller.signal.removeEventListener('abort', onRuntimeAbort);\n\t\t\t\tif (activeController === controller) activeController = undefined;\n\t\t\t\trunning = false;\n\t\t\t\tfinishCompletion();\n\t\t\t\tif (activeCompletion === completion) activeCompletion = undefined;\n\t\t\t}\n\t\t},\n\t\tgetState: () => ({ mutationMayContinue, poisoned, running }),\n\t};\n}\n\nfunction cancellationDidNotSettleResult(startedAt: number, graceMs: number): AgentTerminalResult {\n\treturn {\n\t\taborted: true,\n\t\tdurationMs: Math.max(0, now() - startedAt),\n\t\texitCode: 130,\n\t\tmutationMayContinue: true,\n\t\tpoisoned: true,\n\t\tsettled: false,\n\t\tstderr: `命令取消后未在 ${graceMs} 毫秒内结束;底层执行仍可能继续,运行时已污染。\\n`,\n\t\tstdout: '',\n\t\ttruncated: false,\n\t};\n}\n\nasync function settleWithinCancellationGrace(\n\toutcome: Promise,\n\tgraceMs: number,\n): Promise {\n\tlet timer: ReturnType | undefined;\n\ttry {\n\t\treturn await Promise.race([\n\t\t\toutcome,\n\t\t\tnew Promise((resolve) => {\n\t\t\t\ttimer = setTimeout(() => resolve({ kind: 'grace-expired' }), graceMs);\n\t\t\t}),\n\t\t]);\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t}\n}\n\nfunction resolveCancelSettleGrace(value: number | undefined): number {\n\tif (value === undefined) return DefaultAgentCommandCancelSettleGraceMs;\n\tif (!Number.isFinite(value) || value < 0) throw new RangeError('cancelSettleGraceMs 必须是有限的非负数。');\n\treturn value;\n}\n\nfunction limitedResult(message: string, exitCode: number, isPoisoned: boolean): AgentTerminalResult {\n\treturn {\n\t\tdurationMs: 0,\n\t\texitCode,\n\t\tpoisoned: isPoisoned,\n\t\tsettled: true,\n\t\tstderr: `${message}\\n`,\n\t\tstdout: '',\n\t\ttruncated: false,\n\t};\n}\n\nfunction boundOutput(stdout: string, stderr: string, limit: number) {\n\tconst first = truncateUtf8(stdout, limit);\n\tconst second = truncateUtf8(stderr, Math.max(0, limit - first.bytes));\n\treturn { stdout: first.value, stderr: second.value, truncated: first.truncated || second.truncated };\n}\n\nfunction truncateUtf8(value: string, limit: number): { bytes: number; truncated: boolean; value: string } {\n\tconst bytes = new TextEncoder().encode(value);\n\tif (bytes.byteLength <= limit) return { bytes: bytes.byteLength, truncated: false, value };\n\tlet end = limit;\n\twhile (end > 0 && (bytes[end] & 0xc0) === 0x80) end -= 1;\n\treturn { bytes: end, truncated: true, value: new TextDecoder().decode(bytes.slice(0, end)) };\n}\n\nfunction safeDuration(value: number, startedAt: number): number {\n\treturn Number.isFinite(value) && value >= 0 ? value : Math.max(0, now() - startedAt);\n}\n\nfunction toErrorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction utf8Bytes(value: string): number {\n\treturn new TextEncoder().encode(value).byteLength;\n}\n\nfunction now(): number {\n\treturn typeof performance === 'undefined' ? Date.now() : performance.now();\n}\n", "type": "registry:lib", "target": "@components/blocks/agent-coding/command-runtime.ts" }, { "path": "registry/default/blocks/agent-coding/terminal-history.ts", "content": "import type { AgentTerminalEntry, AgentTerminalResult } from './command-types';\n\nexport const MaxAgentTerminalEntries = 64;\n\nexport function appendAgentTerminalEntry(\n\tentries: readonly AgentTerminalEntry[],\n\tentry: AgentTerminalEntry,\n): AgentTerminalEntry[] {\n\treturn [...entries, entry].slice(-MaxAgentTerminalEntries);\n}\n\nexport function appendCompletedAgentTerminalEntry(\n\tentries: readonly AgentTerminalEntry[],\n\tentry: Pick,\n\tresult: AgentTerminalResult,\n\tfinishedAt = Date.now(),\n): AgentTerminalEntry[] {\n\treturn completeAgentTerminalEntry(\n\t\tappendAgentTerminalEntry(entries, { ...entry, status: 'running' }),\n\t\tentry.id,\n\t\tresult,\n\t\tfinishedAt,\n\t);\n}\n\nexport function completeAgentTerminalEntry(\n\tentries: readonly AgentTerminalEntry[],\n\tid: string,\n\tresult: AgentTerminalResult,\n\tfinishedAt = Date.now(),\n): AgentTerminalEntry[] {\n\treturn entries.map((entry) =>\n\t\tentry.id === id\n\t\t\t? {\n\t\t\t\t\t...entry,\n\t\t\t\t\tfinishedAt,\n\t\t\t\t\tresult,\n\t\t\t\t\tstatus: result.aborted ? 'cancelled' : result.exitCode === 0 ? 'succeeded' : 'failed',\n\t\t\t\t}\n\t\t\t: entry,\n\t);\n}\n", "type": "registry:lib", "target": "@components/blocks/agent-coding/terminal-history.ts" }, { "path": "registry/default/blocks/agent-coding/coding-tools.ts", "content": "import { type ToolSet, tool } from 'ai';\nimport { z } from 'zod';\nimport { type AgentWorkspace, resolveAgentWorkspacePath } from '../agent-work';\nimport { type AgentCommandRuntime, MaxAgentCommandStdinBytes } from './command-runtime';\nimport type { AgentTerminalResult } from './command-types';\n\nexport const MaxAgentWorkspaceWriteBytes = 64 * 1024;\n\nexport type CreateAgentCodingToolsOptions = {\n\tonCommandFinish?: (input: {\n\t\tacquired: boolean;\n\t\tcommand: string;\n\t\tresult: AgentTerminalResult;\n\t\ttoolCallId: string;\n\t}) => void;\n\tonCommandStart?: (input: { command: string; toolCallId: string }) => void;\n\tonWorkspaceChanged?: () => void;\n\truntime: AgentCommandRuntime;\n\tworkspace: AgentWorkspace;\n};\n\nexport function createAgentCodingTools({\n\tonCommandFinish,\n\tonCommandStart,\n\tonWorkspaceChanged,\n\truntime,\n\tworkspace,\n}: CreateAgentCodingToolsOptions): ToolSet {\n\treturn {\n\t\tworkspace_write: tool({\n\t\t\tdescription: '在工作区根目录内写入不超过 64 KiB 的 UTF-8 文件。',\n\t\t\tinputSchema: z.object({\n\t\t\t\tcontent: z.string().max(MaxAgentWorkspaceWriteBytes),\n\t\t\t\tpath: z.string().min(1).max(4096),\n\t\t\t}),\n\t\t\tneedsApproval: true,\n\t\t\texecute: async ({ content, path }, { abortSignal }) => {\n\t\t\t\tconst bytes = utf8Bytes(content);\n\t\t\t\tif (bytes > MaxAgentWorkspaceWriteBytes) {\n\t\t\t\t\treturn { code: 'too-large', limitBytes: MaxAgentWorkspaceWriteBytes, ok: false };\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst resolved = resolveAgentWorkspacePath(workspace.rootPath, path);\n\t\t\t\t\tawait workspace.fileSystem.writeFile(resolved, content, { overwrite: true, signal: abortSignal });\n\t\t\t\t\tonWorkspaceChanged?.();\n\t\t\t\t\treturn { bytes, ok: true, path: resolved };\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn toolError(error);\n\t\t\t\t}\n\t\t\t},\n\t\t}),\n\t\tbash: tool({\n\t\t\tdescription: '通过宿主注入的有界执行器运行非交互命令。',\n\t\t\tinputSchema: z.object({\n\t\t\t\tcommand: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.min(1)\n\t\t\t\t\t.max(16 * 1024),\n\t\t\t\tstdin: z.string().max(MaxAgentCommandStdinBytes).optional(),\n\t\t\t}),\n\t\t\tneedsApproval: true,\n\t\t\texecute: async ({ command, stdin }, { abortSignal, toolCallId }) => {\n\t\t\t\tlet acquired = false;\n\t\t\t\tconst result = await runtime.execute(\n\t\t\t\t\t{ command, stdin },\n\t\t\t\t\t{\n\t\t\t\t\t\tonAcquired: () => {\n\t\t\t\t\t\t\tacquired = true;\n\t\t\t\t\t\t\tonCommandStart?.({ command, toolCallId });\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsignal: abortSignal,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tonCommandFinish?.({ acquired, command, result, toolCallId });\n\t\t\t\tif (result.workspaceChanged) onWorkspaceChanged?.();\n\t\t\t\treturn {\n\t\t\t\t\taborted: result.aborted ?? false,\n\t\t\t\t\tdurationMs: Math.round(result.durationMs),\n\t\t\t\t\texitCode: result.exitCode,\n\t\t\t\t\tpoisoned: result.poisoned ?? false,\n\t\t\t\t\tsettled: result.settled,\n\t\t\t\t\tstderr: result.stderr,\n\t\t\t\t\tstdout: result.stdout,\n\t\t\t\t\ttimedOut: result.timedOut ?? false,\n\t\t\t\t\ttruncated: result.truncated,\n\t\t\t\t\tworkspaceChanged: result.workspaceChanged ?? false,\n\t\t\t\t};\n\t\t\t},\n\t\t}),\n\t};\n}\n\nfunction toolError(error: unknown) {\n\tif (error instanceof Error && error.name === 'AbortError') return { code: 'aborted', ok: false };\n\tconst code =\n\t\ttypeof error === 'object' && error !== null && 'code' in error ? String(error.code).slice(0, 64) : 'failed';\n\treturn { code, message: (error instanceof Error ? error.message : '写入失败。').slice(0, 256), ok: false };\n}\n\nfunction utf8Bytes(value: string): number {\n\treturn new TextEncoder().encode(value).byteLength;\n}\n", "type": "registry:lib", "target": "@components/blocks/agent-coding/coding-tools.ts" }, { "path": "registry/default/blocks/agent-coding/just-bash-executor.ts", "content": "import type { JustBashAgentSession } from '@wener/common/fs/just-bash';\nimport type { AgentCommandExecutor } from './command-types';\n\nexport function createJustBashCommandExecutor(session: JustBashAgentSession): AgentCommandExecutor {\n\treturn {\n\t\tasync execute({ command, stdin }, { signal } = {}) {\n\t\t\tconst result = await session.exec(command, { signal, stdin });\n\t\t\treturn {\n\t\t\t\taborted: result.aborted,\n\t\t\t\tdurationMs: result.durationMs,\n\t\t\t\texitCode: result.exitCode,\n\t\t\t\tmutationMayContinue: result.mutationMayContinue,\n\t\t\t\tpoisoned: result.poisoned,\n\t\t\t\tsettled: result.settled,\n\t\t\t\tstderr: result.stderr,\n\t\t\t\tstdout: result.stdout,\n\t\t\t\ttimedOut: result.timedOut,\n\t\t\t\ttruncated: result.truncated,\n\t\t\t\tworkspaceChanged: result.workspaceChanged,\n\t\t\t};\n\t\t},\n\t};\n}\n", "type": "registry:lib", "target": "@components/blocks/agent-coding/just-bash-executor.ts" }, { "path": "registry/default/blocks/agent-coding/agent-terminal.tsx", "content": "'use client';\n\nimport { Play, Square } from 'lucide-react';\nimport type { ComponentPropsWithRef, FormEvent } from 'react';\nimport { cn } from '@/lib/utils';\nimport type { AgentActiveCommand, AgentTerminalEntry } from './command-types';\n\nexport type AgentTerminalMessages = {\n\tcancel: string;\n\tcommand: string;\n\tempty: string;\n\texitCode: (code: number) => string;\n\tpoisoned: string;\n\trun: string;\n\ttruncated: string;\n};\n\nexport const defaultAgentTerminalMessages: AgentTerminalMessages = {\n\tcancel: '取消命令',\n\tcommand: '命令',\n\tempty: '尚未运行命令。',\n\texitCode: (code) => `退出码 ${code}`,\n\tpoisoned: '执行器已污染,需替换运行时。',\n\trun: '运行命令',\n\ttruncated: '输出已截断',\n};\n\nexport type AgentTerminalProps = ComponentPropsWithRef<'section'> & {\n\tactiveCommand?: AgentActiveCommand;\n\tcommand: string;\n\tentries: readonly AgentTerminalEntry[];\n\tmessages?: Partial;\n\tonCancel?: (id: string) => void;\n\tonCommandChange: (command: string) => void;\n\tonRun?: (command: string) => void;\n\tpoisoned?: boolean;\n};\n\nexport function AgentTerminal({\n\tactiveCommand,\n\tclassName,\n\tcommand,\n\tentries,\n\tmessages,\n\tonCancel,\n\tonCommandChange,\n\tonRun,\n\tpoisoned = false,\n\t...props\n}: AgentTerminalProps) {\n\tconst copy = { ...defaultAgentTerminalMessages, ...messages };\n\tconst submit = (event: FormEvent) => {\n\t\tevent.preventDefault();\n\t\tconst value = command.trim();\n\t\tif (value && !activeCommand && !poisoned) onRun?.(value);\n\t};\n\treturn (\n\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t\t{activeCommand ? (\n\t\t\t\t\t\n\t\t\t\t) : (\n\t\t\t\t\t\n\t\t\t\t)}\n\t\t\t
\n\t\t\t{poisoned ? (\n\t\t\t\t
\n\t\t\t\t\t{copy.poisoned}\n\t\t\t\t
\n\t\t\t) : null}\n\t\t\t
\n\t\t\t\t{entries.length === 0 ?

{copy.empty}

: null}\n\t\t\t\t{entries.map((entry) => (\n\t\t\t\t\t\n\t\t\t\t))}\n\t\t\t\t{activeCommand && !entries.some((entry) => entry.id === activeCommand.id) ? (\n\t\t\t\t\t
\n\t\t\t\t\t\t$ {activeCommand.command}\n\t\t\t\t\t\t{'\\n'}运行中…\n\t\t\t\t\t
\n\t\t\t\t) : null}\n\t\t\t
\n\t\t\n\t);\n}\n\nfunction TerminalEntryView({ entry, copy }: { entry: AgentTerminalEntry; copy: AgentTerminalMessages }) {\n\tconst result = entry.result;\n\treturn (\n\t\t\n\t\t\t$ {entry.command}\n\t\t\t{'\\n'}\n\t\t\t{result?.stdout ?? ''}\n\t\t\t{result?.stderr ? {result.stderr} : null}\n\t\t\t{result ? (\n\t\t\t\t\n\t\t\t\t\t{'\\n'}[{copy.exitCode(result.exitCode)} · {Math.round(result.durationMs)} ms\n\t\t\t\t\t{result.truncated ? ` · ${copy.truncated}` : ''}]\n\t\t\t\t\n\t\t\t) : (\n\t\t\t\t运行中…\n\t\t\t)}\n\t\t\n\t);\n}\n", "type": "registry:component", "target": "@components/blocks/agent-coding/agent-terminal.tsx" }, { "path": "registry/default/blocks/agent-coding/agent-coding.tsx", "content": "'use client';\n\nimport { TerminalSquare } from 'lucide-react';\nimport type { ComponentPropsWithRef } from 'react';\nimport { AgentWork, type AgentWorkProps, type AgentWorkTab } from '../agent-work';\nimport { AgentTerminal, type AgentTerminalMessages } from './agent-terminal';\nimport type { AgentActiveCommand, AgentTerminalEntry } from './command-types';\n\nexport type AgentCodingMessages = {\n\tterminalTab: string;\n};\n\nexport const defaultAgentCodingMessages: AgentCodingMessages = {\n\tterminalTab: '终端',\n};\n\nexport type AgentCodingProps = Omit & {\n\tactiveCommand?: AgentActiveCommand;\n\tcommand: string;\n\tentries: readonly AgentTerminalEntry[];\n\textraWorkspaceTabs?: readonly AgentWorkTab[];\n\tmessages?: AgentWorkProps['messages'] & Partial;\n\tonCancelCommand?: (id: string) => void;\n\tonCommandChange: (command: string) => void;\n\tonRunCommand?: (command: string) => void;\n\tpoisoned?: boolean;\n\tterminalMessages?: Partial;\n\tterminalProps?: Omit, 'children'>;\n};\n\nexport function AgentCoding({\n\tactiveCommand,\n\tcommand,\n\tentries,\n\textraWorkspaceTabs = [],\n\tmessages,\n\tonCancelCommand,\n\tonCommandChange,\n\tonRunCommand,\n\tpoisoned,\n\tterminalMessages,\n\tterminalProps,\n\t...workProps\n}: AgentCodingProps) {\n\tconst fileManagerProps = {\n\t\t...workProps.fileManagerProps,\n\t\treadOnly: poisoned || workProps.fileManagerProps?.readOnly,\n\t};\n\tconst codingCopy = { ...defaultAgentCodingMessages, ...messages };\n\tconst terminal = (\n\t\t\n\t);\n\treturn (\n\t\t\n\t\t\t\t\t\t\t