Hive 终端工具退出码权威指南从 POSIX 约定到语义化退出状态【免费下载链接】hiveMulti-Agent Harness for Production AI项目地址: https://gitcode.com/gh_mirrors/hive48/hive导读本文是 Hive 项目中terminal-tools工具集的退出码速查与深度解析。它面向所有调用terminal_exec、terminal_job_logs等终端工具的 Agent 与开发者系统讲解 POSIX 退出码约定、信号导致的负退出码、以及 Hive 特有的「语义化退出状态」semantic_status机制——后者正是避免把grep无匹配、diff有差异这类正常退出 1误判为错误的关键。读完本文你将掌握完整退出码解读体系、exit_code为null时的三类场景以及如何通过源码与测试证据验证这些行为。本文内容主体源自 references/exit_codes.md它是 terminal-tools-foundations 技能 的配套参考文档。一、POSIX 退出码约定先建立基准心智模型任何进程退出时都会向父进程传递一个 0255 范围内的整数状态码。POSIX 约定是 Agent 解读一切退出结果的起点Hive 的terminal-tools完全遵循这一约定Code含义0成功Success1一般错误 / 兜底错误General error / catchall2Shell 内建命令误用、语法错误Misuse of shell builtins, syntax error126命令已找到但不可执行Command found but not executable127命令未找到Command not found128exit的参数无效Invalid argument toexit128 N被信号 N 杀死Killed by signal N130被 SIGINT 杀死Ctrl-C137被 SIGKILL 杀死143被 SIGTERM 杀死255退出状态超出范围Exit status out of range核心规则0永远表示成功非零值表示某种失败或特殊信息126/127专门用于启动失败而128 N这一组是 shell 层面对进程被信号终止的编码方式信号编号 128。二、负退出码envelope 中的信号化编码在 Hive 的标准 envelope 中exit_code还有一套与 shell 约定不同的编码——当exit_code 0时进程是被信号杀死的此时abs(exit_code)就是信号编号Whenexit_code 0in the envelope, the process was killed by a signal:abs(exit_code)is the signal number (subprocess uses negative codes for signaled exits, separate from the128 Nshell convention).这源于 Pythonsubprocess的行为进程被信号终止时returncode是负数信号号例如被 SIGKILL 杀死返回-9而不是 shell 的128 9 137。两种编码并存但语义清晰负退出码-N出现在 Hive envelope 的exit_code字段来自subprocess原生返回abs(exit_code)即信号编号128 N出现在你直接运行 bash 并让 shell 报告$?时是 shell 层面对信号终止的再编码。源码中exec.py在构建 envelope 时显式传递signaled(exit_code is not None and exit_code 0)见 exec.py而 JobManager 在后台作业结束时用更严格的判定record.signaled rc 0 or (rc ! 0 and abs(rc) in _SIGNAL_NUMBERS)见 jobs/manager.py——即只要返回码为负或非零且绝对值恰好落在已知信号编号集合内SIGINT、SIGTERM、SIGKILL、SIGHUP、SIGUSR1、SIGUSR2 等见同文件_SIGNAL_NUMBERS定义就判定为信号化退出。这一信息最终被semantic_exit.classify()转换为(signal, Killed by signal (exit {exit_code}))即 envelope 中的semantic_status: signal。三、语义化退出什么时候 exit 1 完全不是错误这是整个文档中最关键的实战知识点。许多常见命令把退出码 1 用作正常的信息性结果而非错误。如果 Agent 只读原始exit_code就会把grep没匹配到、diff文件有差异这类完全正常的结果误判为失败。terminal-tools将这些语义编码在semantic_status字段中Agent 应优先读取semantic_status命令退出码 0退出码 1退出码 ≥2grep/rg/ripgrep找到匹配matches found无匹配正常不是错误错误find成功部分目录不可读正常信息性错误diff文件相同文件不同正常信息性错误test/[条件为真条件为假正常信息性错误对不在该表中的任何命令默认约定仍然成立0 正常非零 错误。这套语义表的实现位于 tools/src/terminal_tools/common/semantic_exit.py核心数据结构_SEMANTICS精确对应文档表格_SEMANTICS: dict[str, dict[int, tuple[SemanticStatus, str | None]]] { grep: {0: (ok, None), 1: (ok, No matches found)}, rg: {0: (ok, None), 1: (ok, No matches found)}, ripgrep: {0: (ok, None), 1: (ok, No matches found)}, find: {0: (ok, None), 1: (ok, Some directories were inaccessible)}, diff: {0: (ok, None), 1: (ok, Files differ)}, test: {0: (ok, None), 1: (ok, Condition is false)}, [: {0: (ok, None), 1: (ok, Condition is false)}, }classify()函数的判定优先级依次为超时timed_out→error→ 信号化signaled→signal→ 退出码为Noneok对应 auto-backgrounded 仍在运行→ 查表命中 → 兜底默认语义。表内命令的已知退出码之外的取值如grep的 2、3…一律按error处理保证不会误把真正的失败放行。值得一提的实现细节_base_command会从 argv 或命令字符串中提取基础命令名剥离/usr/bin/之类的前缀并且对管道链只考察最后一个命令因为 shell 传播的是管道末尾的退出码。对shellTrue的字符串这种取最后一段的解析是显式标注的启发式官方注释指出它仅供标注语义、不涉及安全边界见 semantic_exit.py。测试验证exit 1 semantic_status ok仓库测试 test_terminal_tools_exec.py 直接固化了这一行为def test_grep_no_matches_is_ok_not_error(exec_tool, tmp_path): f tmp_path / haystack.txt f.write_text(apples\nbananas\n) result exec_tool(commandfgrep zzz {f}) assert result[exit_code] 1 assert result[semantic_status] ok assert No matches found in (result[semantic_message] or )同文件的test_diff_files_differ_is_ok_not_error亦验证diff两文件不同时exit_code 1且semantic_status ok、semantic_message含differ。这两个用例是理解何时读semantic_status而非裸exit_code的最佳实证。实操规则规则一永远先检查semantic_status。它只有三档ok/signal/error。规则二仅当你确实需要精确数值时例如区分make的 1 与 2才回退到exit_code。规则三看到semantic_status: ok且semantic_message为No matches found/Files differ时不要恐慌——这是命令在正常履行职责。四、exit_code 为 null三种必须区分的场景envelope 中的exit_code并非总是整数文档明确列出null的三种情形auto_backgrounded: true——进程仍在运行已被移交到后台作业持有job_id。此时应改用terminal_job_logs轮询支持since_offset增量读取、wait_until_exit阻塞等待见 jobs/tools.py而不是把null当作失败。Pre-spawn 错误命令未找到、exec 失败——此时 envelope 的error字段会给出具体原因。实现上对应 exec.py 中的_err_envelope()捕获FileNotFoundError返回command not found: ...捕获其他OSError返回spawn failed: ...并置semantic_status: error、exit_code: null。测试test_terminal_tools_exec.py也断言了此场景semantic_status error或error字段存在、semantic_message含not found。timed_out: true且进程拒绝退出——极为罕见此时内核才有答案如僵尸进程或不可中断的 D 状态不要指望从退出码获得信息。注意classify()对exit_code is None且未超时、未被信号化的情形返回(ok, Still running)——这正是 auto-backgrounded 场景的语义化表达见 semantic_exit.py。五、常见信号导致的退出速查表文档给出两套信号编码的对照是排查进程为何非零退出的高频查表信号编号Subprocess 退出码Shell 退出码含义SIGHUP1-1129终端挂断Terminal hangupSIGINT2-2130中断Ctrl-CSIGQUIT3-3131退出Ctrl-\SIGKILL9-9137强制杀死不可捕获SIGTERM15-15143礼貌终止SIGSEGV11-11139段错误SIGABRT6-6134中止断言失败等读表要点Subprocess 退出码负值 Hive envelope 中exit_code的取值abs()即信号号Shell 退出码128 N 你在交互式 bash 中执行echo $?得到的值同一个信号在两套体系中数值不同解读前先确认数据来源。在 Hive 的作业工具中信号操作被封装为具名动作terminal_job_control支持signal_termSIGTERM、signal_killSIGKILL、signal_intSIGINT、signal_hupSIGHUP、signal_usr1、signal_usr2文档建议按先signal_int优雅中断 → 数秒后signal_term→ 最后signal_kill的顺序逐级升级见 jobs/tools.py。六、退出码在标准 envelope 中的完整位置退出码不是孤立字段它与semantic_status、semantic_message、warning等共同构成terminal_exec的标准返回结构完整 envelope 定义见 terminal-tools-foundations SKILL{ exit_code: 0, // null 时见上文第四节 semantic_status: ok, // ok | signal | error — 优先读它 semantic_message: null, // 如 grep 无匹配时的 No matches found warning: null, // 如 rm -rf 的 may force-remove files auto_backgrounded: false, // true 时 exit_code 为 null转 job_id 轮询 job_id: null, timed_out: false, shell_kind: bash // bash | powershell | cmd | direct }envelope 的组装逻辑集中在 common/truncation.pybuild_exec_envelope()先做输出截断默认max_output_kb 256溢出时把完整字节存到output_handle再调用classify()得出semantic_status/semantic_message最后通过get_warning()附加破坏性命令警告。退出码解读、输出截断、破坏性警告三者是一套整体机制semantic_status是其中承载退出码语义的一等公民。七、实战总结Agent 解读退出码的四步流程结合文档与源码推荐所有调用终端工具的 Agent 遵循以下流程先看semantic_statusok直接继续signal查信号表判断是被谁杀的常见为signal_int/signal_term/signal_killerror再往下看。exit_code为null检查auto_backgrounded/job_id转为轮询、error字段pre-spawn 失败、timed_out内核级异常。exit_code非零但semantic_status为ok这是grep/rg/find/diff/test的信息性退出读取semantic_message了解具体含义。exit_code为负abs()即信号编号对照上表如-9 SIGKILL、-15 SIGTERM还原真相。这套约定让终端工具返回退出码从一串难懂的整数变成了 Agent 可直接执行的决策信号——这也是 terminal-tools-foundations 将读懂semantic_status而非裸exit_code列为必读技能的根本原因跳过它就会把grep无匹配误判为错误、把正常退出的后台任务当成丢失产生工具返回空输出式的误报与恐慌。【免费下载链接】hiveMulti-Agent Harness for Production AI项目地址: https://gitcode.com/gh_mirrors/hive48/hive创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
