You need to enable JavaScript to run this app.
文档中心
复制全文
下载 pdf
企业 Hook
企业 Hook 配置详解
复制全文
下载 pdf
企业 Hook 配置详解
本文档介绍企业 Hook 的配置方式、执行环境、输入输出规范,以及各类事件的触发与处理机制。​
Hook 配置​
Hook 配置格式​
每个 Hook 事件配置为一个 JSON 数组。数组中的每个对象表示一个 Hook 组,matcher 用于匹配工具名称或通知类型;SessionStart、UserPromptSubmit、Stop 三类非工具匹配事件无需配置 matcher。​
​
[​
{​
"matcher": "{ToolPattern}",​
"loop_limit": 5,​
"hooks": [​
{​
"type": "http",​
"url": "{URL to send the POST request to}",​
"timeout": 30,​
"headers": {​
"Authorization": "Bearer ...."​
},​
"on_failure": "block"​
}​
]​
}​
]​
​
字段说明​
Hook 相关字段的说明如下:​
  • Hook 组层​
  • ​
  • ​
    字段​
    类型​
    是否必填​
    描述​
    matcher​
    string​
    否​
    匹配规则,支持正则表达式(如 Edit\|Write、mcp.*)。配置为 *、空字符串或省略时,表示匹配所有工具或通知类型。​
    提示:matcher 字段仅对 PreToolUse、PostToolUse 和 Notification 事件有效。​
    loop_limit​
    number​
    否​
    Stop 事件的循环次数限制。​
    当 loop_count ≥ loop_limit 时,该 Hook 组将被跳过。​
    该字段仅支持正整数;未配置或配置的值小于等于 0 时,使用默认值 5。​
    提示:loop_limit 字段仅对 Stop 事件有效。​
    hooks​
    array​
    是​
    该 Hook 组下要执行的 Hook 列表。​
    ​
  • Hook 定义层​
  • ​
  • ​
    字段​
    类型​
    是否必填​
    描述​
    type​
    string​
    否​
    Hook 类型,企业 Hook 当前仅支持 HTTP 类型,取值为 http。​
    url​
    string​
    是​
    接收 Hook 请求的企业服务端 URL。TRAE 会向该 URL 发送 HTTP POST 请求。​
    timeout​
    number​
    否​
    请求超时时间,单位为秒,默认值为 30。​
    headers​
    string​
    否​
    随请求发送的自定义请求头,以键值对形式配置(如用于鉴权的 Authorization)。暂不支持占位符和环境变量。​
    on_failure​
    string​
    否​
    Hook 执行失败时的处理策略:​
    • block:阻断当前问答,中断对话。未配置时默认使用该策略。​
    • skip:跳过该 Hook 的执行,继续当前对话。​
    提示:仅 3.4.9 及更高版本的 TRAE 客户端支持该参数,TraeWork、TRAE Plugin 和 TRAE CLI 尚未支持。​
    ​
HTTP 调用约定​
企业 Hook 通过 HTTP 请求调用企业自有服务。TRAE 会向配置的 url 发送 POST 请求,并通过 HTTP 状态码和响应体判断后续执行行为。​
  • 请求方法:POST​
  • 请求头:固定包含 Content-Type: application/json;若在 Hook 定义中配置了 headers,其中的自定义请求头会一并附加到该请求中。​
  • 请求体:当前 Hook 事件的 JSON payload。通用字段见 “请求体通用字段” 部分,事件专有字段见 “Hook 事件” 部分。​
  • 超时策略:超过 timeout 配置的时长仍未收到响应时,按执行失败处理。​
  • 状态码:​
  • ​
  • ​
    HTTP 状态码​
    响应体​
    行为​
    2xx​
    空​
    继续执行,无附加行为。​
    2xx​
    纯文本​
    在 SessionStart 和 UserPromptSubmit 事件中,将文本作为上下文附加给模型。若为其他事件,则继续执行。​
    2xx​
    JSON​
    继续执行,并按 JSON 内容执行流程控制;若返回 continue: false,则让智能体停止执行。​
    非 2xx​
    任意​
    阻断当前问答。​
    超时 / 连接失败​
    —​
    阻断当前问答。​
    ​
提示​
企业 Hook 依赖企业服务端的可用性。建议为 Hook 服务配置超时、监控和降级策略,避免因服务异常影响用户问答流程。​
Hook 输入和输出​
企业 Hook 的输入输出由 HTTP 请求体和响应体承载:请求体用于传递当前事件上下文,响应体用于返回流程控制结果或附加上下文。​
请求体通用字段​
每个 Hook 事件的请求体 JSON 均包含以下通用字段:​
​
{​
"session_id": "session_id",​
"cwd": "/path/to/workspace",​
"hook_event_name": "PreToolUse",​
"workspace_roots": ["/path/to/workspace"],​
"agent_id": "agent_id",​
"agent_type": "agent_type",​
"email": "user@example.com",​
"model": "model"​
}​
​
​
​
字段​
类型​
描述​
session_id​
string​
当前会话 ID。​
cwd​
string​
当前会话所在的工作区目录。​
hook_event_name​
string​
当前 Hook 事件的名称。​
workspace_roots​
string[]​
如果存在多个工作区,此字段将包含所有工作区的根目录。​
agent_id​
string​
当前执行 Hook 的智能体 ID。​
agent_type​
string​
当前执行 Hook 的智能体类型。​
email​
string​
触发本次 Hook 的成员邮箱。​
model​
string​
当前会话使用的模型标识。​
​
响应体通用字段​
端点可在响应体中返回两种格式的数据:​
  • JSON :用于结构化地控制智能体的执行流程。​
  • 纯文本:输出内容将作为附加上下文提供给模型。此格式仅适用于 SessionStart 和 UserPromptSubmit 事件。​
对于 JSON 格式的输出,所有事件均支持以下通用流程控制字段:​
​
{​
"continue": true,​
"stopReason": "string"​
}​
​
​
​
字段​
类型​
描述​
continue​
boolean​
智能体是否在 Hook 执行完毕后继续执行。默认值为 true。若设置为 false,智能体将停止执行。该字段优先于任何事件特定的 decision 字段。​
stopReason​
string​
当 continue 为 false 时,展示给用户的智能体停止执行的原因。​
​
提示​
Notification 是非阻断事件,不使用响应体进行流程控制。​
Hook 事件​
SessionStart​
  • 触发时机:创建 Session 后、发起第一个对话之前触发。​
  • Hook 的作用:在会话开始时向模型注入上下文信息。​
  • 请求体:​
  • ​
    {​
    "session_id": "...",​
    "hook_event_name": "SessionStart",​
    "source": "startup"​
    }​
    ​
  • 该事件的专有字段如下:​
  • ​
  • ​
    字段​
    类型​
    描述​
    source​
    string​
    会话的来源。目前仅支持 startup(新建会话)。​
    ​
  • 响应体:​
  • 格式一:纯文本​
  • 直接返回纯文本内容,将其作为附加上下文提供给模型。​
  • 格式二:JSON​
  • ​
    {​
    "hookSpecificOutput": {​
    "hookEventName": "SessionStart",​
    "additionalContext": "文本内容"​
    }​
    }​
    ​
  • ​
    字段​
    类型​
    描述​
    additionalContext​
    string​
    附加给模型的上下文。​
    ​
  • 失败行为:如果 Hook 服务返回非 2xx 状态码、请求超时或连接失败,按 HTTP 调用约定处理。​
UserPromptSubmit​
  • 触发时机:用户发送消息后、智能体开始处理前。​
  • Hook 的作用:拦截不允许的请求,或向模型附加上下文。​
  • 请求体:​
  • ​
    {​
    "session_id": "...",​
    "hook_event_name": "UserPromptSubmit",​
    "prompt": "用户输入的 Prompt"​
    }​
    ​
  • 该事件的专有字段如下:​
  • ​
  • ​
    字段​
    类型​
    描述​
    prompt​
    string​
    用户提交的 Prompt 文本。​
    ​
  • 响应体:​
  • 格式一:纯文本​
  • 直接返回非 JSON 格式的纯文本内容,将其作为附加上下文提供给模型。​
  • 格式二:JSON​
  • ​
    {​
    "decision": "block",​
    "reason": "该请求不被允许的原因",​
    "hookSpecificOutput": {​
    "hookEventName": "UserPromptSubmit",​
    "additionalContext": "附加给模型的上下文"​
    }​
    }​
    ​
  • ​
    字段​
    类型​
    描述​
    decision​
    string​
    该字段仅支持设为 block。设置后,将禁止智能体执行该 Prompt。如需允许智能体执行该 Prompt,请将该字段留空。​
    reason​
    string​
    当 decision 字段的值为 block 时,此字段的内容将作为错误信息展示给用户。否则,该字段将被忽略。​
    additionalContext​
    string​
    附加给模型的上下文文本。​
    ​
  • 失败行为:如果 Hook 服务返回非 2xx 状态码、请求超时或连接失败,按 HTTP 调用约定处理。​
PreToolUse​
  • 触发时机:智能体发起工具调用后、实际执行前。​
  • Hook 的作用:校验或拦截工具调用、修改工具参数,或要求用户确认后再执行。​
  • matcher 字段配置:可通过 matcher 字段配置正则表达式,从而匹配特定的工具名。​
  • 请求体:​
  • ​
    {​
    "session_id": "...",​
    "hook_event_name": "PreToolUse",​
    "tool_use_id": "toolcall-id-string",​
    "tool_name": "RunCommand",​
    "llm_tool_name": "RunCommand",​
    "tool_input": { ... }​
    }​
    ​
  • 该事件的专有字段如下:​
  • ​
  • ​
    字段​
    类型​
    描述​
    tool_use_id​
    string​
    工具调用的唯一 ID。​
    tool_name​
    string​
    标准化的工具名称。详见 “PreToolUse 和 PostToolUse 事件支持的工具” 部分。​
    llm_tool_name​
    string​
    传递给大语言模型的原始工具名称。​
    tool_input​
    object​
    工具输入参数。​
    ​
  • 响应体:​
  • ​
    {​
    "hookSpecificOutput": {​
    "hookEventName": "PreToolUse",​
    "permissionDecision": "allow", ​
    "permissionDecisionReason": "决策原因说明",​
    "updatedInput": { ... },​
    "additionalContext": "附加给模型的上下文"​
    }​
    }​
    ​
  • ​
    字段​
    类型​
    说明​
    permissionDecision​
    string​
    权限决策,用于决定是否执行本次工具调用。可选值包括:​
    • allow:允许执行。​
    • deny:拒绝执行。​
    • ask:弹出确认框,由用户决定是否执行。​
    特殊情况说明:​
    • 如果多个 PreToolUse 事件的 Hook 正并行执行,permissionDecision 只会返回一个最终值。取值优先级为: deny -> ask -> allow。​
    • 如果返回值为 allow,但是该工具的运行模式为手动确认,则仍以工具运行模式为准,需要用户确认。​
    permissionDecisionReason​
    string​
    权限决策的原因。​
    updatedInput​
    object​
    修改后的工具输入参数,将整体覆盖替换原始参数(非合并更新)。​
    additionalContext​
    string​
    附加给模型的上下文文本。​
    ​
  • 失败行为:如果 Hook 服务返回非 2xx 状态码、请求超时或连接失败,按 HTTP 调用约定处理。​
PostToolUse​
  • 触发时机:工具调用实际执行完成后。​
  • Hook 的作用:校验执行结果或附加上下文。​
  • matcher 字段配置:可通过 matcher 字段配置正则表达式,从而匹配特定的工具名。​
  • 请求体:​
  • ​
    {​
    "session_id": "...",​
    "hook_event_name": "PostToolUse",​
    "tool_use_id": "toolcall-id-string",​
    "tool_name": "RunCommand",​
    "llm_tool_name": "RunCommand",​
    "tool_input": { ... },​
    "tool_response": { ... }​
    }​
    ​
  • 该事件的专有字段如下:​
  • ​
  • ​
    字段​
    类型​
    描述​
    tool_use_id​
    string​
    工具调用的唯一 ID。​
    tool_name​
    string​
    标准化的工具名称。详见 “PreToolUse 和 PostToolUse 事件支持的工具” 部分。​
    llm_tool_name​
    string​
    传递给大语言模型的原始工具名称。​
    tool_input​
    object​
    工具输入参数。​
    tool_response​
    object​
    工具调用的结果。​
    ​
  • 响应体:​
  • ​
    {​
    "decision": "block",​
    "reason": "阻断原因",​
    "hookSpecificOutput": {​
    "hookEventName": "PostToolUse",​
    "additionalContext": "附加给模型的上下文"​
    }​
    }​
    ​
  • ​
    字段​
    类型​
    描述​
    decision​
    string​
    该字段仅支持设为 block。设置后,会向模型传递一条阻断信息,表示工具已执行且无法撤销。如需允许智能体继续处理工具调用的结果,将该字段留空。​
    reason​
    string​
    当 decision 字段的值为 block 时,此字段的内容将作为阻断原因展示给用户。否则,该字段将被忽略。​
    additionalContext​
    string​
    附加给模型的上下文文本。​
    ​
  • 失败行为:如果 Hook 服务返回非 2xx 状态码、请求超时或连接失败,按 HTTP 调用约定处理。​
Stop​
  • 触发时机:智能体完成输出、准备结束当前查询时。此时,你可以检查智能体的输出是否达标;若不达标,可以阻止智能体结束任务并要求其继续处理。​
  • Hook 的作用:阻止智能体结束当前任务,并要求其继续执行。​
  • 请求体:​
  • ​
    {​
    "session_id": "...",​
    "hook_event_name": "Stop",​
    "stop_hook_active": false,​
    "loop_count": 0, ​
    "last_assistant_message": "大语言模型最终输出的文本内容"​
    }​
    ​
  • 该事件的专有字段如下:​
  • ​
  • ​
    字段​
    类型​
    描述​
    stop_hook_active​
    boolean​
    当前查询是否已经被 Stop 事件的 Hook 至少阻断过一次。​
    loop_count​
    number​
    当前查询的 Stop 事件被 Hook 阻断的次数计数。从 0 开始累加。​
    循环限制:你可以通过 loop_limit 字段配置该 Hook 组允许阻断 Stop 事件的最大次数。当 loop_count ≥ loop_limit 时,该 Hook 组将被跳过,使智能体不再执行,以避免无限循环。loop_limit 的默认值为 5。​
    last_assistant_message​
    string​
    大语言模型最终输出的文本内容。​
    ​
  • 响应体:​
  • ​
    {​
    "decision": "block",​
    "reason": "请继续检查测试是否通过"​
    }​
    ​
  • ​
    字段​
    类型​
    描述​
    decision​
    string​
    该字段仅支持设为 block。设置后,将阻断智能体停止执行。如需让智能体停止执行,将该字段留空。​
    reason​
    string​
    当 decision 字段的值为 block 时,此字段的内容将作为新的用户请求让智能体继续执行。否则,该字段将被忽略。​
    ​
  • 失败行为:如果 Hook 服务返回非 2xx 状态码、请求超时或连接失败,按 HTTP 调用约定处理。​
  • 决策控制流程:​
  • Stop 事件的决策控制逻辑如下:​
  • ​
    智能体准备停止​
    │​
    ▼​
    检查 loop_count 是否大于等于 loop_limit?──── 是 ──► 跳过 Hook,允许智能体停止​
    │​
    否​
    │​
    ▼​
    调用 Stop 事件的企业 Hook 服务​
    │​
    ├── 返回 2xx 状态码,且 decision 字段为空 ───────► 允许停止​
    │​
    ├── 返回 2xx 状态码,且 decision 字段的值为 block ──► 阻断停止,将 reason 字段作为新 Query​
    │​
    └── 非 2xx 状态码 / 超时 / 连接失败 ───────────► 按 HTTP 调用约定处理​
    ​
Notification​
  • 触发时机:智能体的工具调用等待用户确认时,或智能体完成任务时。该事件异步执行,不会阻塞智能体的主流程。​
  • Hook 的作用:发送通知,不改变智能体的执行流程。​
  • matcher 字段配置:基于通知类型(notification_type)匹配,而不是基于工具名匹配。未配置 matcher,或将其配置为空字符串或 * 时,表示匹配所有通知类型。​
  • 请求体:​
  • ​
    {​
    "session_id": "...",​
    "hook_event_name": "Notification",​
    "notification_type": "idle_prompt",​
    "message": "智能体已完成任务",​
    "tool_use_id": "toolu_xxx"​
    }​
    ​
  • 该事件的专有字段如下:​
  • ​
  • ​
    字段​
    类型​
    描述​
    notification_type​
    string​
    通知类别,用于标识通知场景,也用于匹配 matcher 字段的配置。可选值见下表。​
    message​
    string​
    通知的正文。​
    tool_use_id​
    string?​
    关联的工具调用 ID。​
    仅工具调用相关的通知类型携带该 ID,例如 permission_prompt、document_review 等。任务完成时发送的 idle_prompt 类通知不携带该 ID。​
    ​
  • notification_type 字段的值和相应触发时机如下:​
  • ​
  • ​
    值​
    触发时机​
    idle_prompt​
    智能体完成当前任务。​
    permission_prompt​
    工具调用需要用户确认后才能继续执行,例如当 PreToolUse 事件的 Hook 返回 ask 决策,或工具本身需要手动确认时。​
    document_review​
    Plan 或 Spec 工作流中的文档审阅流程。​
    ask_user_question​
    智能体需要用户补充信息时,进行提问的通知。​
    browser_interaction​
    浏览器交互等待通知。​
    ​
  • 响应体:该事件不使用响应体进行流程控制。即使服务端返回 JSON,也不会改变智能体的行为。​
  • 失败行为:Notification 为非阻断事件。即使 Hook 服务返回非 2xx 状态码、请求超时或连接失败,也不会改变智能体的执行流程。​
PreToolUse 和 PostToolUse 事件支持的工具​
在 PreToolUse 和 PostToolUse 事件中,你可以通过 matcher 字段匹配 tool_name。​
tool_name 为标准化工具名称,取值如下:​
​
​
分类​
工具名称​
描述​
文件读取​
Read​
读取文件内容。​
文件写入​
Write​
写入文件。​
文件编辑​
Edit​
单次查找并替换文件内容。​
搜索​
Glob​
基于文件路径模式进行匹配搜索。​
​
Grep​
基于正则表达式进行内容搜索。​
​
LS​
列出目录下的文件与子目录。​
终端​
RunCommand​
执行终端命令。​
网络​
WebSearch​
网络搜索。​
​
WebFetch​
获取网页内容。​
交互​
AskUserQuestion​
向用户提问。​
Skill​
Skill​
加载 Skill。​
MCP​
mcp__<serverName>__<toolName>​
MCP 工具。​
MCP 工具匹配说明:在 Hook 中,MCP 工具的标准化名称格式为 mcp__<serverName>__<toolName>(例如 mcp__Git__iCube__git_status)。你可以在 matcher 字段中使用 mcp__.* 来匹配所有 MCP 工具,或使用具体工具的名称进行精确匹配。​
​
示例​
事件配置​
​
SessionStart
UserPromptSubmit
PreToolUse
PostToolUse
Stop
Notification
​
​
[​
{​
"hooks": [​
{​
"type": "http",​
"url": "http://localhost:9000/session-start"​
}​
]​
}​
]​
​
​
请求体示例​
​
SessionStart
UserPromptSubmit
PreToolUse
PostToolUse
Stop
Notification
​
​
{​
"session_id": "6a321771xxxxxx1312bfebd8",​
"cwd": "/Users/example/Documents/code/hooks_test",​
"hook_event_name": "SessionStart",​
"workspace_roots": [​
"/Users/example/Documents/code/hooks_test"​
],​
"agent_id": "dev_agent",​
"agent_type": "dev_agent",​
"source": "startup",​
"email": "zhangsan@example.com",​
"model": "auto/Trae"​
}​
​
​
服务端点​
这段示例代码提供了一个可在本地运行的 TRAE 企业 HTTP Hook 调试服务。服务启动后会监听 9000 端口,并为 SessionStart、UserPromptSubmit、PreToolUse、PostToolUse、Stop 和 Notification 这些 Hook 事件分别提供 HTTP endpoint。TRAE 触发 Hook 时,会将事件请求体发送到对应 endpoint;服务端会在终端打印完整的请求体和响应体,便于你检查字段结构、事件触发时机和流程控制结果。你可以直接使用该示例验证企业 Hook 配置是否生效,也可以基于它扩展企业内部的权限校验、审计记录、上下文注入或通知逻辑。​
​
#!/usr/bin/env python3​
import json​
import sys​
from copy import deepcopy​
from datetime import datetime​
from http.server import BaseHTTPRequestHandler, HTTPServer​
from urllib.parse import urlparse​
​
PORT = 9000​
​
ROUTES = {​
"/session-start": {​
"event": "SessionStart",​
"description": "会话开始时触发,默认继续执行。",​
},​
"/user-prompt-submit": {​
"event": "UserPromptSubmit",​
"description": "用户提交 Prompt 后触发,默认继续执行。",​
},​
"/user-prompt-submit/block": {​
"event": "UserPromptSubmit",​
"action": "block",​
"description": "示例:阻断用户请求。",​
},​
"/pre-tool-use": {​
"event": "PreToolUse",​
"description": "工具执行前触发,默认继续执行。",​
},​
"/pre-tool-use/block-read": {​
"event": "PreToolUse",​
"action": "block_read",​
"description": "示例:阻断 Read 工具。",​
},​
"/pre-tool-use/ask": {​
"event": "PreToolUse",​
"action": "ask",​
"description": "示例:要求用户确认后再执行工具。",​
},​
"/post-tool-use": {​
"event": "PostToolUse",​
"description": "工具执行后触发,默认继续执行。",​
},​
"/stop": {​
"event": "Stop",​
"description": "智能体准备结束当前查询时触发,默认允许停止。",​
},​
"/stop/continue": {​
"event": "Stop",​
"action": "continue",​
"description": "示例:阻止智能体停止,并要求继续处理。",​
},​
"/notification": {​
"event": "Notification",​
"description": "通知事件,非阻断,响应体不影响智能体流程。",​
},​
}​
​
DEFAULT_RESPONSES = {​
"SessionStart": {},​
"UserPromptSubmit": {},​
"PreToolUse": {},​
"PostToolUse": {},​
"Stop": {},​
"Notification": {},​
}​
​
​
def json_dumps(data: dict) -> str:​
return json.dumps(data, indent=2, ensure_ascii=False)​
​
​
def print_event(event_name: str, path: str, payload: dict, response: dict) -> None:​
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]​
sep = "─" * 80​
​
print(f"\n{'━' * 80}")​
print(f" TRAE Hook Event: {event_name}")​
print(f" Time: {ts}")​
print(f" POST http://localhost:{PORT}{path}")​
print(sep)​
print("[request]")​
print(json_dumps(payload))​
print(sep)​
print("[response]")​
print(json_dumps(response))​
print(sep)​
sys.stdout.flush()​
​
​
def build_response(route: dict, payload: dict) -> dict:​
event_name = route["event"]​
action = route.get("action")​
​
if action == "block":​
return {​
"decision": "block",​
"reason": "该请求被企业 Hook 策略阻断。",​
}​
​
if action == "block_read":​
tool_name = payload.get("tool_name")​
if tool_name == "Read":​
return {​
"hookSpecificOutput": {​
"hookEventName": "PreToolUse",​
"permissionDecision": "deny",​
"permissionDecisionReason": "Read 工具已被企业 Hook 策略阻断。",​
}​
}​
​
return {}​
​
if action == "ask":​
return {​
"hookSpecificOutput": {​
"hookEventName": "PreToolUse",​
"permissionDecision": "ask",​
"permissionDecisionReason": "该工具调用需要用户确认后再执行。",​
}​
}​
​
if action == "continue":​
return {​
"decision": "block",​
"reason": "请继续检查当前回答是否完整,并补充必要的验证结果。",​
}​
​
return deepcopy(DEFAULT_RESPONSES[event_name])​
​
​
class HookHandler(BaseHTTPRequestHandler):​
def log_message(self, fmt, *args):​
return​
​
def send_json(self, data: dict, status: int = 200) -> None:​
body = json.dumps(data, ensure_ascii=False).encode("utf-8")​
​
self.send_response(status)​
self.send_header("Content-Type", "application/json; charset=utf-8")​
self.send_header("Content-Length", str(len(body)))​
self.end_headers()​
self.wfile.write(body)​
​
def do_GET(self):​
path = urlparse(self.path).path​
​
if path == "/":​
self.send_json(​
{​
"status": "ok",​
"name": "TRAE Enterprise HTTP Hooks Server",​
"port": PORT,​
"routes": ROUTES,​
}​
)​
return​
​
self.send_json({"error": f"not found: {path}"}, status=404)​
​
def do_POST(self):​
path = urlparse(self.path).path​
route = ROUTES.get(path)​
​
if route is None:​
self.send_json({"error": f"unknown hook path: {path}"}, status=404)​
return​
​
length = int(self.headers.get("Content-Length", 0))​
raw = self.rfile.read(length) if length else b"{}"​
​
try:​
payload = json.loads(raw.decode("utf-8"))​
except json.JSONDecodeError as exc:​
self.send_json(​
{​
"error": "invalid JSON request body",​
"detail": str(exc),​
},​
status=400,​
)​
return​
​
response = build_response(route, payload)​
print_event(route["event"], path, payload, response)​
self.send_json(response)​
​
​
def main():​
server = HTTPServer(("0.0.0.0", PORT), HookHandler)​
​
print(f"\nTRAE Enterprise HTTP Hooks Server port {PORT}")​
print("─" * 80)​
print("Health check:")​
print(f" GET http://localhost:{PORT}/")​
print("\nHook endpoints:")​
for path, route in ROUTES.items():​
print(​
f" POST http://localhost:{PORT}{path:<32} "​
f"{route['event']:<16} {route.get('description', '')}"​
)​
print("─" * 80)​
print("Waiting for TRAE hook events...\n")​
sys.stdout.flush()​
​
try:​
server.serve_forever()​
except KeyboardInterrupt:​
print("\nStopped.")​
​
​
if __name__ == "__main__":​
main()​
​
​
最近更新时间:2026.11.03 14:56:48
这个页面对您有帮助吗?
有用
有用
无用
无用