Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
ac2eaca
chore: quick update feat/mcp at 2026-03-14 21:26:34
kooksee Mar 14, 2026
2fdfeda
chore: quick update feat/mcp at 2026-03-14 21:35:16
kooksee Mar 14, 2026
1905d7c
chore: quick update feat/mcp at 2026-03-14 21:52:22
kooksee Mar 14, 2026
631d1aa
chore: quick update feat/mcp at 2026-03-14 21:53:56
kooksee Mar 14, 2026
16af237
chore: quick update feat/mcp at 2026-03-14 22:12:33
kooksee Mar 14, 2026
efee0f4
chore: quick update feat/mcp at 2026-03-14 23:56:02
kooksee Mar 14, 2026
3f17731
chore: quick update feat/mcp at 2026-03-15 12:39:34
kooksee Mar 15, 2026
b31be41
chore: quick update feat/mcp at 2026-03-15 13:14:00
kooksee Mar 15, 2026
0514c2a
chore: quick update feat/mcp at 2026-03-15 15:45:34
kooksee Mar 15, 2026
ed07bcc
chore: quick update feat/mcp at 2026-03-15 16:11:45
kooksee Mar 15, 2026
f5c1ada
chore: quick update feat/mcp at 2026-03-17 17:05:10
kooksee Mar 17, 2026
6014c3b
chore: quick update feat/mcp at 2026-03-17 17:07:42
kooksee Mar 17, 2026
176e460
chore: quick update feat/mcp at 2026-03-17 18:26:58
kooksee Mar 17, 2026
7ce0f49
chore: quick update feat/mcp at 2026-03-17 18:27:20
kooksee Mar 17, 2026
6d072df
feat: 新增 readline 命令支持多轮交互 REPL,增强命令补全功能
kooksee Mar 18, 2026
49706b9
chore: quick update feat/mcp at 2026-03-18 16:11:34
kooksee Mar 18, 2026
eb272d7
chore: quick update feat/mcp at 2026-03-18 16:20:19
kooksee Mar 18, 2026
de5549f
chore: quick update feat/mcp at 2026-03-18 16:37:47
kooksee Mar 18, 2026
85b4bd6
feat: 升级 Bubble Tea 和相关依赖,优化命令行交互体验
kooksee Mar 20, 2026
eec21e1
Add unit tests for agentline command handling and user interactions
kooksee Mar 20, 2026
4fa1e77
feat: 增强 agentline 模式支持,新增命令元数据处理与路由机制
kooksee Mar 20, 2026
648fe13
feat: 优化 agentline 命令处理,隐藏别名以减少候选噪音
kooksee Mar 20, 2026
1d74935
feat: 增强命令补全功能,支持命令标志的建议与前缀匹配
kooksee Mar 20, 2026
00589bc
feat: 增加对 Ctrl+C 退出的双重确认支持,优化 readline 错误处理逻辑及单元测试
kooksee Mar 20, 2026
3bf8b10
feat: 增加对空输入时固定初始建议的支持,优化建议处理逻辑及单元测试
kooksee Mar 20, 2026
7824d87
feat: 增加历史命令查看功能,支持通过 /history 命令查看输入历史及限制条数
kooksee Mar 20, 2026
f7307cd
feat: 更新命令提示信息,增加滚轮滚动指令;添加鼠标模式在输出聚焦时的测试
kooksee Mar 20, 2026
c0bcee9
feat: 移除不再支持的 /ask 和 /plan 命令,更新命令提示信息,增强命令补全功能
kooksee Mar 21, 2026
ea674f7
feat: 添加 WebTTY 命令,支持通过 WebSocket 交互终端
kooksee Mar 21, 2026
4c52e38
feat: 添加文件上传功能,支持通过 POST 请求上传文件并处理目录遍历攻击
kooksee Mar 21, 2026
f7c5422
feat: add file upload and download functionality with directory support
kooksee Mar 21, 2026
76aa880
feat(webtty): introduce minimal local Web terminal with file upload/d…
kooksee Mar 21, 2026
d2c5bff
chore: quick update feat/copilot at 2026-03-24 15:41:41
kooksee Mar 24, 2026
8b1c6ac
Merge branch 'feat/mcp' of github.com:pubgo/redant into feat/copilot
kooksee Mar 24, 2026
20981b3
feat: 增强会话管理功能,支持会话摘要恢复与自动执行恢复命令
kooksee Mar 24, 2026
a92c571
feat: 更新 agentline 命令元数据,简化命令标记方式并增强交互体验
kooksee Mar 24, 2026
474ada7
feat: 添加 GitShell 模块,支持 Git 命令执行和分支检测功能
kooksee Mar 24, 2026
5959f47
feat: 移除鼠标功能相关代码,简化交互体验并优化复制操作
kooksee Mar 24, 2026
f165b1b
feat: 添加续聊功能,支持恢复会话并优化命令行输入体验
kooksee Mar 24, 2026
3551160
Refactor and enhance agentline command handling and UI
kooksee Mar 24, 2026
ad9c3df
chore: quick update feat/copilot at 2026-03-24 23:13:14
kooksee Mar 24, 2026
2c1c6b0
feat: 更新 agentline 相关命令,增强交互体验与可读性
kooksee Mar 24, 2026
4f40542
feat: Implement ACP Client and Permission Management
kooksee Mar 24, 2026
16cb7ae
feat: 增强 ACP 交互能力,新增权限审批命令与会话恢复功能
kooksee Mar 24, 2026
319a65d
feat: 增强聊天模式支持,添加命令建议与错误提示功能
kooksee Mar 25, 2026
5cae692
feat: 增强聊天命令的补全功能,添加命令标志建议与前缀处理
kooksee Mar 25, 2026
25a5b48
Refactor code structure for improved readability and maintainability
kooksee Mar 25, 2026
a50dad1
Implement feature X to enhance user experience and optimize performance
kooksee Mar 25, 2026
20e6925
feat: 添加 .local 目录到 .gitignore 文件
kooksee Mar 25, 2026
2d19b6e
feat: 增强 ACP 观测能力,新增事件时间线、统计摘要与导出功能
kooksee Mar 25, 2026
ff383df
feat: 新增 Go 编码、发布前变更与测试开发约束文档
kooksee Mar 25, 2026
d917068
feat: add question handling commands and interaction protocol
kooksee Mar 25, 2026
845096f
refactor: remove agentline module and related metadata from commands
kooksee Mar 25, 2026
5464510
feat: 精简仓库结构,将 agentline 和 copilot-demo 迁移至独立项目,更新文档以反映变更
kooksee Mar 25, 2026
6dce805
feat: 增强 Richline 交互终端体验,新增状态提示与焦点切换功能
kooksee Mar 25, 2026
f754ea5
feat: 更新 Richline 交互终端样式,增强输入输出区域的可视化提示与焦点状态
kooksee Mar 25, 2026
0910246
feat: 支持直接执行业务命令并增强 slash 命令补全功能
kooksee Mar 25, 2026
610199b
fix: 修复 collectTopLevelSlashCommandItems 函数中的语法错误
kooksee Mar 25, 2026
594924f
feat: 增强 slash 命令补全功能,支持命令标志、参数和枚举值的提示
kooksee Mar 25, 2026
cdcd360
feat: 增加 GitHub 行级评论发布功能,支持按需将问题项写入 PR 评论并返回链接
kooksee Mar 25, 2026
654e476
feat: 增加 PR 行级评论统一模板,支持去重和统一格式,减少沟通噪音
kooksee Mar 26, 2026
56e3c89
feat: 新增 PR 评论功能,支持自动生成和发布评论,增强代码审查效率
kooksee Mar 26, 2026
1e65c8b
feat: 新增代码审查综合指南,整合最佳实践与问题分类检测
kooksee Mar 26, 2026
0d94825
feat: Add comprehensive PR review guidelines and templates
kooksee Mar 26, 2026
4cd2d89
feat: 更新代码审查指引,增加审查模式入口及分类标签要求
kooksee Mar 26, 2026
1c55008
feat: 在 PR 审查中新增 Round 4 结论要求,包含全分类勾选清单及标注
kooksee Mar 26, 2026
924e642
feat: 更新 PR 审查代理和指令,默认发布行级评论并优化用户交互
kooksee Mar 26, 2026
af687a5
feat: 更新 PR 分轮审查代理工具列表,增加 VSCode 相关工具和执行命令
kooksee Mar 26, 2026
078b772
feat: 精简 PR 分轮审查代理工具列表,移除冗余执行命令
kooksee Mar 26, 2026
3f7c534
feat: 更新 PR 行级评论模板,统一分类格式并增加问题分类选项
kooksee Mar 26, 2026
37da31a
feat: 更新 PR 审查代理和模板,统一分类格式并增加去重要求
kooksee Mar 26, 2026
2834213
feat: 添加 isExpectedPTYReadClose 函数及其单元测试,优化错误处理逻辑
kooksee Mar 26, 2026
ebe4393
feat: 更新 PR 审查代理和规范,增强审查模式与门禁自检逻辑
kooksee Mar 26, 2026
56b5f91
feat: 删除 publish_round1_template_comments.sh 脚本,简化代码库
kooksee Mar 27, 2026
b52c1f5
feat: 更新高风险路径列表要求,允许列出所有路径
kooksee Mar 27, 2026
1ae748e
feat: 优化测试命令,动态获取测试包列表并执行测试
kooksee Mar 27, 2026
1627159
Merge branches 'feat/acp' and 'main' of github.com:pubgo/redant
kooksee Mar 27, 2026
059b7ed
Merge branch 'main' of github.com:pubgo/redant
kooksee Mar 30, 2026
82bd460
feat: 增加流式处理能力,支持结构化响应输出与交互式命令
kooksee Mar 30, 2026
3222b99
feat: add support for streaming command execution via WebSocket
kooksee Mar 31, 2026
b0b6a9f
feat: 重构响应流处理,简化数据发送方式,支持直接发送字符串
kooksee Mar 31, 2026
9cc9871
feat: 更新注释以明确响应流处理中的数据类型,优化新建流的逻辑
kooksee Mar 31, 2026
dd7cd11
feat: 移除响应缓冲区配置,使用默认缓冲区大小简化流响应处理
kooksee Apr 1, 2026
9d691a5
feat: 移除冗余的响应处理代码,重构流处理逻辑以增强可读性和可维护性
kooksee Apr 1, 2026
e282d07
feat: 删除旧的测试文件并添加新的处理程序测试以增强代码覆盖率
kooksee Apr 1, 2026
3b6d13e
feat: 重命名适配器函数以符合命名约定,增强代码一致性
kooksee Apr 1, 2026
a5f8506
feat: 重构流处理逻辑,新增泛型适配器与响应流处理器,优化文档与示例
kooksee Apr 1, 2026
9424c0d
feat: 增加对流处理的支持,更新工具定义以包含响应类型和流标志,增强输出模式
kooksee Apr 1, 2026
4cca0c3
feat: 更新文档与示例,增强 Unary 和流式处理器的说明,新增示例代码
kooksee Apr 1, 2026
cabe752
feat: 更新设计文档中的图表,增强可读性和一致性
kooksee Apr 1, 2026
c5a36c7
feat: 新增流式输出测试命令,支持每秒发送一条数据
kooksee Apr 1, 2026
75088fb
feat: 增强流响应处理,新增 NDJSON 信封结构,更新测试以验证输出格式
kooksee Apr 1, 2026
e5b3562
chore: release v0.2.0 changelog
kooksee Apr 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .version/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.1.0
v0.2.0
1 change: 1 addition & 0 deletions .version/changelog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
## 当前版本文件

- [`Unreleased.md`](Unreleased.md)
- [`v0.2.0.md`](v0.2.0.md)
- [`v0.1.0.md`](v0.1.0.md)
- [`v0.0.6.md`](v0.0.6.md)
- [`v0.0.5.md`](v0.0.5.md)
Expand Down
9 changes: 4 additions & 5 deletions .version/changelog/Unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@

## 新增

- 暂无
暂无

## 修复

- 暂无
暂无

## 变更

- 暂无
暂无

## 文档

- 暂无

暂无
37 changes: 37 additions & 0 deletions .version/changelog/v0.2.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# [v0.2.0] - 2026-04-01

## 新增

- 增加 `InvocationStream`,支持命令在执行期间进行响应流输出。
- 增加 `Invocation.ResponseStream()` 返回 `<-chan any`,由命令内部创建并暴露响应流供调用方消费。
- 增加 `ResponseHandler` / `ResponseStreamHandler` 接口化处理器,并提供 `Unary[T]` / `Stream[T]` 泛型适配器以携带运行时类型信息。
- 增加 `TypedWriter[T]` 泛型写入器,通过 `Send(v T)` 直接发送泛型数据到流通道。
- 增加 `RunCallback[T]` 泛型回调执行入口,统一支持 Unary 响应与 Stream 输出的类型化回调分发。
- 增加 `StreamError` 结构化错误类型,支持 `code/message/details`。
- 增加 `StreamEnvelope` NDJSON 信封类型(`{"$":"resp","type":"T","data":...}`),stdout/stderr 镜像输出使用信封包装,消费者可通过 `$` 键区分响应数据与普通日志。
- `InvocationStream.Send` 自动镜像输出:响应数据以 NDJSON 信封写入 stdout,`StreamError` 以信封写入 stderr;channel 消费者仍接收原始值。
- 新增 `example/fastcommit stream` 流式输出测试命令,每秒发送一条带时间戳的消息。

## 修复

- 修复 `InvocationStream.Send` 与 `closeResponseStream` 之间的并发竞态:channel 引用在创建时捕获,不再动态读取。

## 变更

- 流通道类型从 `chan map[string]any` 简化为 `chan any`,直接传递泛型数据,不再包装事件结构。
- 三类处理器互斥校验前移到 `init` 阶段:`Handler`、`ResponseHandler`、`ResponseStreamHandler` 同时配置时报错。
- 适配器函数 `adaptResponseHandler` / `adaptResponseStreamHandler` 改为包内私有。
- `handler.go` / `response_handlers.go` / `execution_typed.go` 合并为单一 `handler.go`。
- 对应测试文件 `execution_typed_test.go` / `stream_test.go` 合并为 `handler_test.go`。
- 移除 `Command.ResponseBuffer` 字段,流通道缓冲统一使用内部默认值。
- `webcmd/webui` 增加 `/api/run/stream/ws` 流式 WebSocket 执行通道。
- `webcmd/webui` 命令元数据 `/api/commands` 增加 `supportsStream` 字段。

## 文档

- 更新 `docs/DESIGN.md` 第 9 节,反映三类处理器互斥与泛型适配器架构,补充 Unary 执行路径与执行上下文兼容矩阵。
- 重写 `docs/INTERACTIVE_STREAMING.md`,更新为 `TypedWriter[T].Send` + `chan any` 模型;新增 Unary 执行路径、`ResponseTypeInfo` 说明、执行上下文兼容性表、MCP 集成章节。
- 更新 `docs/USAGE_AT_A_GLANCE.md`,新增第 8 节(Unary ResponseHandler)、第 9 节(Stream ResponseStreamHandler)、第 10 节(三类处理器对比表)。
- 更新 `docs/DOCS_CATALOG.md`,补充 `example/unary` 与 `example/stream-interactive` 示例引用。
- 新增 `example/unary` 示例及说明文档,展示 `Unary[T]` + `RunCallback[T]` 用法。
- 新增 `example/stream-interactive` 示例及说明文档。
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ MCP 输入/输出协议、Schema 规则与排查建议见:[`docs/MCP.md`](docs
- `example/env-test`:环境变量示例
- `example/globalflags`:全局标志示例
- `example/args-test`:参数解析示例
- `example/stream-interactive`:交互流(结构化输出 + 内建响应流)完整示例

## 开发与维护

Expand Down
113 changes: 108 additions & 5 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ type Command struct {

// Middleware is called before the Handler.
// Use Chain() to combine multiple middlewares.
Middleware MiddlewareFunc
Handler HandlerFunc
Middleware MiddlewareFunc
Handler HandlerFunc
ResponseHandler ResponseHandler
ResponseStreamHandler ResponseStreamHandler
}

func ascendingSortFn[T cmp.Ordered](a, b T) int {
Expand Down Expand Up @@ -121,6 +123,10 @@ func (c *Command) init() error {
}
}

if _, err := c.resolveConfiguredHandler(); err != nil {
merr = errors.Join(merr, err)
}

slices.SortFunc(c.Options, func(a, b Option) int {
// Use Flag for sorting, fallback to Env if Flag is empty
nameA := a.Flag
Expand Down Expand Up @@ -272,6 +278,9 @@ type Invocation struct {
Stderr io.Writer
Stdin io.Reader

responseStream chan any
responseValue any

// Annotations is a map of arbitrary annotations to attach to the invocation.
Annotations map[string]any

Expand Down Expand Up @@ -329,13 +338,60 @@ func (inv *Invocation) WithTestParsedFlags(
})
}

// ResponseStream returns the invocation response stream channel.
//
// The stream is internally owned by Invocation and is closed automatically when
// ResponseStreamHandler execution finishes.
func (inv *Invocation) ResponseStream() <-chan any {
return inv.ensureResponseStream()
}

func (inv *Invocation) ensureResponseStream() chan any {
if inv.responseStream != nil {
return inv.responseStream
}
inv.responseStream = make(chan any, defaultStreamResponseBuffer)
return inv.responseStream
}

func (inv *Invocation) closeResponseStream() {
if inv.responseStream == nil {
return
}
ch := inv.responseStream
inv.responseStream = nil
close(ch)
}

func (inv *Invocation) Context() context.Context {
if inv.ctx == nil {
return context.Background()
}
return inv.ctx
}

// Response returns the unary response produced by ResponseHandler in current run.
func (inv *Invocation) Response() (any, bool) {
if inv == nil || inv.responseValue == nil {
return nil, false
}
return inv.responseValue, true
}

func (inv *Invocation) setResponse(v any) {
if inv == nil {
return
}
inv.responseValue = v
}

func (inv *Invocation) clearResponse() {
if inv == nil {
return
}
inv.responseValue = nil
}

func (inv *Invocation) ParsedFlags() *pflag.FlagSet {
if inv.Flags == nil {
panic("flags not parsed, has Run() been called?")
Expand Down Expand Up @@ -846,7 +902,7 @@ func (inv *Invocation) run(state *runState) error {

ctx, cancel := context.WithCancel(ctx)
defer cancel()
inv = inv.WithContext(ctx)
inv.ctx = ctx

// Check for help flag
if inv.Flags != nil {
Expand All @@ -855,11 +911,16 @@ func (inv *Invocation) run(state *runState) error {
}
}

if inv.Command.Handler == nil || errors.Is(state.flagParseErr, pflag.ErrHelp) {
handler, resolveErr := inv.Command.resolveConfiguredHandler()
if resolveErr != nil {
return &RunCommandError{Cmd: inv.Command, Err: resolveErr}
}

if handler == nil || errors.Is(state.flagParseErr, pflag.ErrHelp) {
return DefaultHelpFn()(ctx, inv)
}

err := mw(inv.Command.Handler)(ctx, inv)
err := mw(handler)(ctx, inv)
if err != nil {
return &RunCommandError{
Cmd: inv.Command,
Expand Down Expand Up @@ -1060,6 +1121,9 @@ func parseAndSetArgs(argsDef ArgSet, args []string) error {
//
//nolint:revive
func (inv *Invocation) Run() (err error) {
defer inv.closeResponseStream()
inv.clearResponse()

restoreEnv, preloadErr := preloadEnvFromArgs(inv.Args)
if preloadErr != nil {
return fmt.Errorf("preloading environment variables: %w", preloadErr)
Expand Down Expand Up @@ -1213,3 +1277,42 @@ func (c *Command) children() map[string]*Command {
}
return childrenMap
}

func (c *Command) resolveConfiguredHandler() (HandlerFunc, error) {
if c == nil {
return nil, nil
}

hasRequest := c.Handler != nil
hasUnary := c.ResponseHandler != nil
hasStream := c.ResponseStreamHandler != nil

configuredCount := 0
if hasRequest {
configuredCount++
}
if hasUnary {
configuredCount++
}
if hasStream {
configuredCount++
}

if configuredCount > 1 {
return nil, fmt.Errorf("command %q configures multiple handler models", c.FullName())
}

if hasRequest {
return c.Handler, nil
}

if hasUnary {
return adaptResponseHandler(c.ResponseHandler), nil
}

if hasStream {
return adaptResponseStreamHandler(c.ResponseStreamHandler), nil
}

return nil, nil
}
44 changes: 44 additions & 0 deletions command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -833,3 +833,47 @@ func TestInternalArgsFlagOverridesParsedArgs(t *testing.T) {
t.Fatalf("second arg value = %q, want %q", gotSecond, "from-flag-2")
}
}

func TestCommandInitHandlerValidation(t *testing.T) {
tests := []struct {
name string
command *Command
wantErr bool
}{
{
name: "invalid multiple handler models configured",
command: &Command{
Use: "echo",
Handler: func(ctx context.Context, inv *Invocation) error {
return nil
},
ResponseHandler: Unary(func(ctx context.Context, inv *Invocation) (string, error) {
return "ok", nil
}),
},
wantErr: true,
},
{
name: "valid response stream handler",
command: &Command{
Use: "chat",
ResponseStreamHandler: Stream(func(ctx context.Context, inv *Invocation, out *TypedWriter[string]) error {
return out.Send("hello")
}),
},
wantErr: false,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
err := tc.command.init()
if tc.wantErr && err == nil {
t.Fatalf("expected init error, got nil")
}
if !tc.wantErr && err != nil {
t.Fatalf("unexpected init error: %v", err)
}
})
}
}
63 changes: 55 additions & 8 deletions docs/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ flowchart LR
R --> O[选项与参数解析层]
O --> M[中间件编排层]
M --> H[处理器执行层]
H --> X[输出/错误/退出码]
H --> X["输出/错误/退出码"]

R --> C1[命令树]
O --> C2[Option 与 Arg]
O --> C2["Option 与 Arg"]
M --> C3[Middleware]
H --> C4[Handler]
```
Expand Down Expand Up @@ -152,13 +152,13 @@ stateDiagram-v2

```mermaid
flowchart LR
UI[浏览器 xterm.js] -->|WebSocket| WS[/ws]
WS --> PTY[PTY 桥接]
PTY --> SH[本地 shell]
UI["浏览器 xterm.js"] -->|WebSocket| WS["/ws"]
WS --> PTY["PTY 桥接"]
PTY --> SH["本地 shell"]

UI -->|multipart| UP[/upload]
UI -->|GET| LS[/api/files]
UI -->|GET| DL[/download]
UI -->|multipart| UP["/upload"]
UI -->|GET| LS["/api/files"]
UI -->|GET| DL["/download"]

UP --> FS[(工作目录)]
LS --> FS
Expand Down Expand Up @@ -232,3 +232,50 @@ sequenceDiagram
- 同级:[`MCP.md`](MCP.md) 提供 MCP 子命令、Schema 与调用协议说明。
- 同级:[`WEBTTY.md`](WEBTTY.md) 提供 WebTTY 能力说明与分阶段迭代路线。
- 下游:[`../example/args-test/README.md`](../example/args-test/README.md) 提供参数解析落地示例。
- 下游:[`../example/unary/README.md`](../example/unary/README.md) 提供 Unary 响应处理器示例。
- 下游:[`../example/stream-interactive/README.md`](../example/stream-interactive/README.md) 提供流式响应处理器示例。

## 9. 交互式命令与流式处理

为兼容传统一次性命令执行,同时支持类 RPC 的结构化响应输出,Redant 新增了 Unary/Stream 处理能力。

### 处理器类型与适配

```mermaid
flowchart LR
A[Invocation.Run] --> B{命令处理器类型}
B -- Handler --> D[原始 HandlerFunc]
B -- ResponseHandler --> E[Unary 适配]
B -- ResponseStreamHandler --> C[Stream 适配]
E --> E1[Handle → 返回 T]
E1 --> E2[setResponse + JSON stdout]
C --> F[InvocationStream]
F --> G[TypedWriter.Send]
G --> H[ResponseStream 通道输出]
H --> I[Run 结束自动 close]
```

### 执行上下文兼容矩阵

```mermaid
flowchart TD
CMD[命令] --> CTX{执行上下文}
CTX -- CLI 直接调用 --> CLI[stdout 自动输出]
CTX -- RunCallback --> RCB[泛型回调分发]
CTX -- MCP callTool --> MCP[RunCallback → structuredContent]
CTX -- WebUI Stream WS --> WS[WebSocket 事件推送]
CTX -- readline / richline --> REPL[降级: stdout 纯文本]
```

设计要点:

1. 保留 `HandlerFunc` 与 `MiddlewareFunc`,不破坏现有执行链。
2. 三类处理器互斥:`Handler`(无响应)、`ResponseHandler`(Unary 单响应)、`ResponseStreamHandler`(流式响应),初始化阶段校验冲突。
3. `ResponseHandler` 通过 `Unary[T]` 泛型适配器构造,返回值自动 JSON 序列化写入 stdout,可通过 `Response()` 或 `RunCallback[T]` 获取。
4. `ResponseStreamHandler` 通过 `Stream[T]` 泛型适配器构造,`TypedWriter[T].Send(v)` 直接发送泛型数据。
5. 响应流通道类型为 `chan any`,通过 `Invocation.ResponseStream()` 消费。
6. `InvocationStream.Send` 自动镜像文本到 stdout、`StreamError` 到 stderr、struct 类型 JSON 序列化到 stdout。
7. `RunCallback[T]` 提供泛型回调消费入口,统一支持 Unary 与 Stream 两种模型的类型化分发。
8. `ResponseTypeInfo` 暴露运行时类型元数据(`TypeName`、`Schema`),供 MCP 等集成层生成输出 Schema。

详见:[`INTERACTIVE_STREAMING.md`](INTERACTIVE_STREAMING.md)。
Loading
Loading