尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

oh-my-pi Bash 工具实战指南:持久 Shell 执行、命令拦截与输出截断机制

发布时间:2026/9/12 4:30:55

资讯中心
01
ARTICLE

oh-my-pi Bash 工具实战指南:持久 Shell 执行、命令拦截与输出截断机制

oh-my-pi Bash 工具实战指南:持久 Shell 执行、命令拦截与输出截断机制
oh-my-pi Bash 工具实战指南持久 Shell 执行、命令拦截与输出截断机制【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi本文是 oh-my-piCoding agent with the IDE wired in中bash 工具toolName: bash的完整技术指南。文章以模型侧提示词文档 bash.md 为骨架结合配套文档 docs/tools/bash.md、运行时说明 docs/bash-tool-runtime.md 与源码实现系统讲解该工具的使用边界、全部输入参数、输出结果形态、双通道命令策略权限策略与专用工具路由、五种执行模式以及输出截断与 artifact 溢出机制。读完本文你将掌握如何正确、安全、高效地驱动 oh-my-pi 的 bash 工具并理解其底层执行引擎的工作原理。工具定位与使用边界bash 工具的核心定位是在持久 Shell 会话中运行命令。它的设计哲学是让 Agent 用最小的代价快速计算一个事实而不是取代所有系统操作工具。模型侧提示词文档 bash.md 明确划定了使用边界应当使用单个二进制程序或一个短管道用于计算一个事实的场景例如wc -l、sort | uniq -c、diff。不应使用内联脚本inline scripts、heredoc、$(…)命令替换、复杂的控制流与引号嵌套、以及非平凡管道。这些场景在会话启用eval工具时路由到eval未启用时应使用专用工具或仓库中已检入的脚本checked-in script。这一边界同时是能力边界而非性能偏好拦截器interceptor只对可以用路径类专用工具替代的简单命令做路由而bash本身承载的是那些无法被read、grep、glob、edit、write覆盖的真实 Shell 计算能力例如进程管理、文件操作与管道数据处理。输入参数详解工具入口为BashTool.execute()实现在 packages/coding-agent/src/tools/bash.ts。完整参数如下字段类型必填说明commandstring是要执行的 Shell 命令文本。当cwd未提供时开头的cd path ...会被重写为cwd字段并从命令中剥离。envRecordstring, string否附加环境变量。键名必须匹配^[A-Za-z_][A-Za-z0-9_]*$否则抛出错误。值会经过内部 URL 展开以环境值而非 Shell 文本的形式传入。timeoutnumber否超时秒数默认300。0表示禁用截止时间。正值先受tools.maxTimeout全局上限约束再被钳制到 Bash 范围1..3600秒。cwdstring否工作目录相对session.cwd通过resolveToCwd解析必须存在且为目录。ptyboolean否请求 PTY 模式默认false。仅在pty: true、PI_NO_PTY ! 1且工具上下文具备 UI 时生效。asyncboolean否后台执行请求。仅当会话启用async.enabled时出现。立即返回 job id 而不等待不改变有效截止时间包括timeout: 0的禁用状态。超时钳制规则超时钳制逻辑见 packages/coding-agent/src/tools/tool-timeouts.tsexport const TOOL_TIMEOUTS { bash: { default: 300, min: 1, max: 3600 }, // ... } as const satisfies Recordstring, ToolTimeoutConfig; export function clampTimeout(tool: ToolTimeoutConfig, rawTimeout?: number, maxTimeout?: number): number { const config TOOL_TIMEOUTS[tool]; const timeout rawTimeout ?? config.default; const capped maxTimeout ! undefined maxTimeout 0 ? Math.min(timeout, maxTimeout) : timeout; return Math.max(config.min, Math.min(config.max, capped)); }关键语义全局上限tools.maxTimeout也会钳制默认回退路径即 Agent 省略timeout时而不仅仅是显式传入的值maxTimeout 0表示不设全局上限。当发生钳制时#buildCompletedResult()/#buildBackgroundStartResult()会在结果中追加一行说明。内部 URL 展开expandInternalUrls()会重写command、每个env值以及疑似协议的cwd值中的内部 URL如skill://、agent://、local://。三种位置的替换方式不同这是源码中的一个关键细节command中的替换经过Shell 转义shell-escapedenv与cwd中的替换使用noEscape: true因为它们将成为环境值/文件系统路径不会插值进 Shell 文本因而采用原始值。local://路径还会通过expandInternalUrls(..., { ensureLocalParentDirs: true })在执行前创建父目录。输出与结果形态工具返回一个text内容块加可选的details。stdout 与 stderr 在模型看到之前合并确定的非零退出码会以Command exited with code n追加到错误结果文本末尾。前台成功content[0].text命令输出无输出时为(no output)。details.timeoutSeconds经过全局/工具级钳制后的有效正超时timeout: 0时则为details.timeoutDisabled: true。details.requestedTimeoutSeconds当请求的正超时与有效超时不一致时出现。details.wallTimeMs本地/客户端终端运行完成的墙钟毫秒数。details.terminalId经客户端终端桥client terminal bridge执行时出现。details.exitCode命令以非零码完成时出现。details.timedOut: true本地/PTY 超时结果上出现。details.meta.truncation输出在内存中被截断时出现完整输出溢出到 artifact 时附带artifactId。非零退出与本地/PTY 超时返回标记为isError的工具结果。后台启动async: true或自动后台化content[0].text可选的前缀尾部与提示末尾为Backgrounded as job id; result will be delivered automatically.details.async{ state: running, jobId, type: bash }后台的进度与完成通过onUpdate/ 异步 job 管理器送达运行中更新携带尾部文本与details.async.state: running完成/失败更新携带最终文本与details.async.state: completed | failed。非零退出或超时被记录为失败的后台 job。失败取消、缺失退出状态、校验失败、被拦截命令以及客户端终端桥超时会抛出ToolError/ToolAbortError。使用指令与最佳实践模型侧提示词文档 bash.md 给出了一组必须遵守的操作规范它们是驱动该工具的正确姿势用cwd而非cd设置cwd字段代替cd需要多行或引号繁重的值时应使用env: { NAME: … }传参而不是拼进命令字符串。pty: true仅用于终端交互典型场景是sudo、ssh这类需要真实 TTY 交互的命令。顺序依赖的命令用放进一次调用相互独立的调用可以并发执行非 PTY 调用默认concurrency: shared同一条 assistant 消息里的多个 bash 调用并行运行。内部 URI 自动解析为路径skill://、agent://等内部协议在命令、env、cwd 中自动展开。async: true延迟有限命令的结果但不会延长timeout——后台化不改变有效截止时间。关键禁令critical提示词中的critical块定义了不可妥协的规则绝不使用 Shell 的grep/rg应使用内置grep工具其尊重.gitignore并返回结构化结果。用read列目录、用glob找路径绝不使用ls/find。避免head、tail和重定向输出会被捕获、截断并链接为artifact://idShell 侧的手工截断反而会丢失完整输出。服务、watcher、调试器与 REPL 必须使用hubop:start让进程保持可观测、可管理而不是用nohup或 Shell 后台语法放飞。辅助内置工具集当hasShellBuiltins为真时持久 Shell 会话注册了一组进程内辅助工具由 pi-shell 提供mkdir, wc, sort, comm, diff, uniq, base64, cmp, md5sum, sha{1,224,256,384,512}sum, b2sum, basename, dirname, readlink, realpath, touch, stat, date, mktemp, seq, yes, printenv, truncate, tac, nproc, uname, whoami, hostname, which, ps, pgrep, pkill, pidwait, top, cut, tee, tr, paste, sed, xargs, jq, rm, mv, ln, ts, sponge, ifne, isutf8, combine非 Windows 另有errno。这意味着大部分管道运算无需依赖系统外部二进制且行为高度一致。双通道命令策略权限策略与专用工具路由文档 docs/tools/bash.md 指出有两套相互独立的设置可以阻止 Bash 子进程启动它们目的不同、在工具调用生命周期的不同阶段运行设置目的规则语法命中结果bash.patterns命令级执行策略带*通配符的纯文本放行 / 请求人工批准 / 拒绝bashInterceptor.patterns优先使用专用工具JavaScript 正则可选 flags 工具名 消息返回 Bash 工具错误告知模型调用指定专用工具选择原则一句话用bash.patterns回答命令能不能执行用bashInterceptor.patterns回答这个操作该由哪个工具执行。bash.patterns权限策略规则有序首个匹配者生效。每条规则含matchglob 与approval值allow/prompt/denybash: patterns: - match: git * approval: allow - match: curl * approval: prompt - match: rm -rf * approval: deny行为要点deny在BashTool.execute()运行前就终止调用包括yolo模式。prompt展示批准请求仅被接受的请求继续执行。allow可以为简单命令降低审批层级但不能批准复合命令——match: git *不会放行git status rm -rf build。deny与prompt会检查完整命令以及每个 Shell 命令段因此cd /tmp rm -rf build也会被rm -rf *规则捕获。bashInterceptor.patterns专用工具路由拦截器是默认关闭bashInterceptor.enabled默认false的选入式路由层专为技术上合法、但用现有专用工具表达更佳的命令设计bashInterceptor: enabled: true patterns: - pattern: ^\s*(cat|head|tail)\s tool: read message: Use the read tool instead; it handles binary files and provides better context. - pattern: ^\s*(grep|rg)\s tool: grep message: Use the grep tool instead; it respects .gitignore and returns structured results.拦截器规则仅在对应tool在当前会话可用时生效。若read被禁用指向read的cat规则就不会拦截 Bash 调用——这是尽力而为的能力偏好而非安全边界。内置默认规则定义于DEFAULT_BASH_INTERCEPTOR_RULESpackages/coding-agent/src/config/settings-schema.ts覆盖五类常见误用文件读取类cat|head|tail|less|more→read搜索类grep|rg|ripgrep|ag|ack→grep查找类find|fd|locate带-name/-iname/-type/-glob等标志→glob原地编辑sed -i、perl -i、awk -i inplace→edit重定向写入echo|printf|cat 带→write以及nohup、后台语法、dev/start/watch类服务进程 →hub。拦截器的匹配策略拦截器始终先检查完整原始命令再检查由未被引号包裹/转义的、||、;、|、|、或换行分隔的扁平命令片段最后检查去掉开头NAMEvalue赋值后的片段。例如git add file git commit -m message GIT_AUTHOR_NAMEDev git commit -m message锚定规则^\s*git\scommit\b因此能同时匹配两个例子中的git commit。一个重要的例外通过未加引号的|或|消费另一命令 stdout 的阶段不算拦截候选如printf x\n | grep x中的grep x因为路径类专用工具无法提供管道 stdin。heredoc、参数展开、命令替换、反引号、分组与畸形引号只保留完整命令检查——拦截器刻意不做成一个完整的 Shell 解析器。两套策略的交互批准策略在执行前解析deny永不抵达拦截器prompt只有在用户接受批准后才进入拦截器。若被接受的调用随后命中拦截规则Bash 调用仍然不会运行模型会收到路由错误并应调用专用工具。因此应避免在两个地方配置同一操作例如cat *的prompt规则加上cat→read拦截器会先请求批准 Bash、再拒绝 Bash 并让模型改用read——两步行为通常不是期望结果。执行管线从命令规范化到结果返回BashTool.execute()的执行管线在 docs/tools/bash.md 中被分解为 16 步核心环节如下读取command、校验env键名不合法抛ToolError(Invalid bash env name: key)默认timeout为300。cwd缺省时将开头的cd path ...重写进结构化cwd字段并从命令中剥离前缀。async: true而async.enabled关闭时在任何执行前抛出ToolError。拦截器开启时checkBashInterception()对原始命令与cd剥离后的命令分别检查规则顺序完整输入 → 扁平片段 → 去掉NAMEvalue前缀的片段命中即在 URL 展开前抛出。expandInternalUrls()重写命令、env 值与 cwd 中的内部 URL命令替换做 Shell 转义env/cwd 用原始值。resolveToCwd()相对session.cwd解析cwdfs.stat()校验存在且为目录。timeout: 0禁用截止时间否则clampTimeout(bash, ...)应用全局上限与1..3600范围。执行路径分叉显式async→ 托管后台 job非 PTY 自动后台化 → 托管 job 并等待min(thresholdMs, timeoutMs - 1000)客户端终端桥 → 远程终端否则前台执行。前台非 PTY 无客户端终端时调用executeBash()packages/coding-agent/src/exec/bash-executor.ts该路径自行执行 direnv/devenv 预检。前台 PTY 与客户端终端路径在分发前执行同样的 direnv 预检。bash.direnv: auto默认时允许的.envrc可能合并环境变更off则禁用。bash.direnvLoadTimeoutMs默认30_000正超时也会约束预检。本地路径在有session.allocateOutputArtifact时先分配输出 artifact大输出可溢出到磁盘。executeBash()加载 Shell 设置、可选 Shell 快照与 minimizer 设置通过持久原生Shell会话或一次性executeShell()运行。runInteractiveBashPty()创建PtySession叠加 xterm 控制台 UI转发按键输入通过OutputSink捕获输出。客户端终端桥调用session.getClientBridge().createTerminal(...)发出terminalId更新轮询输出直至退出/超时/中止信号退出映射为137。完成时#buildCompletedResult()格式化(no output)、附加截断元数据与墙钟/超时/退出说明。本地/PTY 超时成为带details.timedOut的isError结果客户端终端超时与取消路径在附带捕获输出时抛出。五种执行模式前台非 PTY 本地无客户端终端桥时的默认路径走executeBash()通过streamTailUpdates()与TailBuffer(DEFAULT_MAX_BYTES)流式输出尾部更新。前台非 PTY 客户端终端session.getClientBridge()?.capabilities.terminal为真、存在createTerminal且pty为 false 时使用以details.terminalId轮询当前终端输出实施相同超时与中止行为随后释放终端句柄。前台 PTY需pty: true、UI 上下文与PI_NO_PTY ! 1使用runInteractiveBashPty()与PtySession叠加层支持交互输入在叠加层按Esc可终止会话。PTY 路径不做非交互硬化继承用户环境设置真实TERMxterm-256color让编辑器、分页器与 TUI 表现为普通终端。显式后台 jobasync: true且async.enabled开启立即注册 job 并返回{ state: running, jobId }timeout: 0表示无工具强加截止时间。自动后台化非 PTY jobbash.autoBackground.enabled、无 PTY/客户端终端桥且 job 管理器未达运行上限超出等待窗口后转后台达容量时回退为前台直跑。被拦截命令不创建子进程返回指向read、grep、glob、edit或write的ToolError。自动后台化的阈值自动后台化默认阈值60_000msDEFAULT_AUTO_BACKGROUND_THRESHOLD_MS定义于 packages/coding-agent/src/tools/bash.ts有截止时间时进一步封顶为timeoutMs - 1000timeout: 0的禁用截止时间使阈值不被封顶。非交互执行引擎Shell 会话复用、jq 兼容与 direnv会话复用模型executeBash()在进程级全局 map 中缓存原生Shell实例键为Shell 路径、配置的命令前缀、快照路径、序列化的 Shell 环境、可选的 Agent 会话键、minimizer 配置。工具调用传入sessionKey: this.session.getSessionId?.()bang 命令传入sessionId实现按会话隔离复用。并发调用绝不共享同一个Shell原生会话一次只运行一个命令Shell.abort()会杀掉其上所有进行中的运行。executeBash()用shellSessionsInUse跟踪进行中键键忙时重叠调用跳过缓存改用一次性executeShell()与隔离会话相同。只有持有者释放占用标志或删除缓存会话。内置 jq 兼容性除非设置PI_DISABLE_UUTILS_BUILTINS非 PTY 原生 Shell 注册的jq是内置的 jaq 后端而非系统jq。两者行为存在可观测差异jaq 在链式访问穿越 null/缺失中间节点时报错——.a.b作用于{}退出码 5而 jq 返回null。运行时文档建议用[.a.b?][0]保护访问{c: [.a.b?][0]}?抑制 jaq 的遍历错误[…][0]把被抑制的空输出映射为null同时保留合法的false/null。应避免朴素的.a.b? // null//把合法的false及null当作缺失会静默改写布尔数据且{c: .a.b? // null}在 jq 中是语法错误值需加括号{c: (.a.b? // null)}。非交互环境硬化buildNonInteractiveEnv()packages/coding-agent/src/exec/non-interactive-env.ts在调用方与 direnv 覆盖之下叠加非交互硬化默认值分页器禁用PAGERcat、GIT_PAGERcat等LESSFRX编辑器提示禁用GIT_EDITORtrue、EDITORtrue、VISUALtrue终端/凭据提示收敛TERMdumb、GIT_TERMINAL_PROMPT0、SSH_ASKPASS/usr/bin/false、NO_COLOR1、CItrue除非PI_BASH_NO_CI/CLAUDE_BASH_NO_CI已设置npm/pnpm/yarn/pip/cargo/terraform/gh 等包管理器的非交互自动化标志Windows 上补充 UTF-8 locale/codepage 默认值。direnv 提供的变量合并到显式调用方env之下被 direnv 安全移除的变量以unset -v ...前缀形式预置。输出处理流式、截断与 artifact 溢出PTY 与非 PTY 路径统一使用OutputSinkpackages/coding-agent/src/session/streaming-output.ts尾部滚动窗口spillThreshold/DEFAULT_MAX_BYTES目前为50KB溢出时裁剪到尾部UTF-8 边界安全并标记truncated。头部窗口与中间省略headBytes 0tools.artifactHeadBytes默认 20KB时保留头部窗口、省略中间在dump()中于头尾之间拼接省略标记。行宽上限maxColumns 0tools.outputMaxColumns默认 768 字节时超宽行在写入时以省略号截断行内剩余内容丢弃。原始流镜像输出溢出、行宽截断触发或文件已激活时完整原始流镜像到 artifact 文件。模型看到的输出是截断后的尾窗口及可选的头部省略视图完整内容通过artifact://id提供模型可回读。dump()返回output、truncated、totalLines/totalBytes、outputLines/outputBytes、省略字节/行数中间省略时、columnDroppedBytes/columnTruncatedLines行宽触发时与artifactId。此外非 PTY 执行还会把 minimizer 设置传入原生Shell会话当 minimizer 重写冗长输出时执行器用最小化文本替换可见输出原始捕获存为独立bash-originalartifact并可能追加[raw output: artifact://id]footer。运行时文档明确提醒这里的截断基于字节阈值50KB 尾窗 可选头窗并非硬性行数上限。限制、错误与会话注意事项限制与上限速查默认超时300sTOOL_TIMEOUTS.bash.default。timeout: 0禁用命令截止时间正超时钳制范围1..3600s。内存输出尾部上限 50KB流式回调节流 50msTUI 折叠预览 10 视觉行渲染器上限非工具输出上限。非 PTY 执行器带截止时间时宿主侧定时器取max(1_000, timeoutMs)并向原生运行传递同一正超时超时的持久 Shell 会话会被隔离quarantine。错误分类输入校验非法 env 键 →ToolError(Invalid bash env name: key)禁用时请求 async →ToolError(Async bash execution is disabled...)缺失 job 管理器 →ToolError(Background job manager unavailable for this session.)cwd缺失/非目录 →ToolError(Working directory does not exist: ...)/ToolError(Working directory is not a directory: ...)。拦截器命中 →ToolError(Blocked: rule.message)附带原始命令非法正则被compileRules()静默跳过。内部 URL 展开不支持的 scheme、未知 skill、路径穿越、缺失路由支持或路由解析失败均从 bash-skill-urls.ts 抛出ToolError。执行非零退出 →isError结果details.exitCodeCommand exited with code n缺失退出码 →ToolError(Command failed: missing exit status)超时 → 本地/PTY 返回details.timedOut: true客户端终端桥杀终端后抛ToolError用户中止 →ToolAbortError。并发与会话细节BashTool设置strict trueconcurrency逐调用解析pty: true为exclusive独占终端 UI其余为shared因此同一条 assistant 消息中的多个非 PTY bash 调用并行运行。并行调用重叠同一 Shell 会话键时首个持有持久Shell其余使用隔离的一次性 Shell。拦截器仅在匹配规则的tool存在于ctx.toolNames时拦截缺失工具会使对应规则失效。bash.direnv默认auto并遵守 direnv 的 allow 列表——未允许的.envrc不会被执行设为off可跳过预检。PTY 在非 UI 上下文及PI_NO_PTY1时被忽略由canUseInteractiveBashPty()判定回退为非 PTY 并追加pty requested but unavailable in this environment; ran without a terminal提示。两种执行表面工具调用与用户 bang 命令运行时文档强调coding-agent 中存在两个不同的 bash 执行表面工具调用表面toolName: bash模型调用 bash 工具时使用入口BashTool.execute()参数含command、可选env、timeout、cwd、pty及asyncasync.enabled开启时。用户 bang 命令表面交互输入中的!cmd或 RPCbash命令会话级辅助路径入口AgentSession.executeBash()渲染走BashExecutionComponentpackages/coding-agent/src/modes/components/bash-execution.ts交互 UI 组件折叠预览保留最近 20 个逻辑行、单行 4000 字符钳制。两者最终都经由executeBash()执行非 PTY 逻辑但只有工具调用路径运行规范化/拦截、可选托管后台 job 与工具渲染器逻辑。将bash.enabled: false写入设置可从工具注册表中移除模型侧的 bash 工具但这不会禁用用户 bang 命令与 RPCbash请求。进一步阅读工具入口与执行管线packages/coding-agent/src/tools/bash.ts非 PTY 执行器、会话复用与取消packages/coding-agent/src/exec/bash-executor.ts拦截器规则匹配packages/coding-agent/src/tools/bash-interceptor.ts内部 URL 展开packages/coding-agent/src/tools/bash-skill-urls.ts输出流、截断与 artifact 溢出packages/coding-agent/src/session/streaming-output.ts默认拦截器规则与设置 schemapackages/coding-agent/src/config/settings-schema.ts完整工具规范docs/tools/bash.md运行时内部机制会话复用键、快照、前缀处理、原生超时行为docs/bash-tool-runtime.md【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。