Documentation
¶
Overview ¶
会话级环境变量转发:把 SSH_AUTH_SOCK 这类「由会话注入、不来自 dotfile」的 变量解析出来,注入单个终端会话的环境。
职责:
- 按三级顺序解析每个变量:继承 → 平台查询 → 探不到
- 逐个变量记录三态结论,让「终端里 git push 失败」变成一行可搜的日志
边界:
- 只产出**这个会话的** cmd.Env,**绝不写回 agentd 自身环境**。这与 internal/pathenv 相反:PATH 是进程级恒定事实,socket 路径是会话级易变 事实,写回会让后续所有 fork 拿到一个可能已经失效的路径。
- 探不到就是探不到,不编造默认值(spec §4.2)
- 解析失败一律降级为 unavailable,不阻断会话创建
PTY 的 unix 平台原语:开伪终端、起 login shell、调尺寸、按进程组终止。
职责:
- 把 openpty 与进程组信号这两件平台相关的事收敛在本文件
- 向上只暴露与 platform_other.go 完全同签名的五个函数
边界:
- 不认识会话、缓冲、订阅者——那是 ptyhost.go 的事
- 不做参数校验(shell 是否存在等),失败原样上抛
日志:本文件不打日志。所有错误原样上抛,由 ptyhost.go 带着会话 id 统一记录, 避免同一个失败在两层各留一条无法关联的记录。
Package ptyhost 托管伪终端(PTY)会话:开 shell、持有会话表、维护回放缓冲、 向多个订阅者广播输出、按进程组终止。
职责:
- 会话的完整生命周期:创建、写入、订阅、调尺寸、显式关闭、自然退出
- 每会话一个环形缓冲,支撑断线重连的 since 续传
- 多方接入时的尺寸协商(取所有订阅者中的最小值)
边界:
- 不认识 HTTP / WebSocket / JSON,也不认识 agentd 的任务模型
- 不做鉴权,不做 base_path 白名单校验(那是 agentd 接口层的参数校验)
- 不落盘:会话表只在内存里,随 agentd 生死(spec §3.1、§10)
- 不解析终端转义序列,只搬字节
Index ¶
- Variables
- func DefaultEnvForward() []string
- func ResolveEnvForward(names []string, base []string, log *slog.Logger) []string
- type Attachment
- type Host
- func (h *Host) Attach(id string, since uint64) (*Attachment, error)
- func (h *Host) Close(id string) error
- func (h *Host) Get(id string) (Session, bool)
- func (h *Host) List() []Session
- func (h *Host) Open(opt OpenOptions) (Session, error)
- func (h *Host) Supported() bool
- func (h *Host) Write(id string, p []byte) error
- type OpenOptions
- type Session
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNoSession 表示会话 id 不存在(或已被显式关闭)。 ErrNoSession = errors.New("终端会话不存在") // ErrTooManySubscribers 表示该会话的订阅者已达上限。 ErrTooManySubscribers = errors.New("终端会话的连接数已达上限") // ErrSessionExited 表示 shell 已经退出,只能读历史不能再写。 ErrSessionExited = errors.New("终端会话已退出") )
var ErrNotSupported = errors.New("当前平台不支持 PTY 终端")
ErrNotSupported 表示当前平台没有 PTY 实现(Windows:ConPTY 是另一套 API, 本轮如实降级而不假装支持,见 spec §10)。
这个变量刻意放在**无构建标签**的文件里:两套 platform_*.go 都要引用它, 放进任一带标签的文件都会让另一套编译不过。
Functions ¶
func DefaultEnvForward ¶
func DefaultEnvForward() []string
DefaultEnvForward 返回内置默认清单的副本。
返回副本而不是切片本身:调用方(config 解析、测试)拿到后可能就地排序或改写, 那会污染进程内所有后续会话。
func ResolveEnvForward ¶
ResolveEnvForward 把 names 里每个变量按三级顺序解析后追加到 base,返回新环境。
参数:
- names: 要转发的变量名清单(调用方已按 nil→默认清单 归一化)
- base: 会话的基础环境(PATH / TERM 等),原样保留
- log: 逐个变量记录三态结论,不得为 nil
返回:base + 解析成功的 `NAME=VALUE`。探不到的变量**不出现**在结果里。
注意:日志只记变量名与结论来源,**不记变量值**——今天转发的是 socket 路径, 但这份清单是用户可配的,明天可能就有人往里加一个带凭据的变量。
Types ¶
type Attachment ¶
type Attachment struct {
Backlog []byte
Since uint64
Truncated bool
Out <-chan []byte
// contains filtered or unexported fields
}
Attachment 是一次订阅。Backlog 是建连瞬间的历史回放,Out 是后续实时输出; Out 被关闭意味着会话结束(不是网络抖动),客户端应停止重连。
func (*Attachment) Detach ¶
func (a *Attachment) Detach()
Detach 退订。**只断连接,不动进程**——这是 spec §3.2 的核心分工: 关页面、切设备、组件卸载一律走这里,杀会话只有 Close 一条路。
func (*Attachment) Resize ¶
func (a *Attachment) Resize(cols, rows int) error
Resize 上报本订阅者的尺寸,并按「所有订阅者取最小」重新协商实际尺寸。
type Host ¶
type Host struct {
// contains filtered or unexported fields
}
Host 是本机所有 PTY 会话的持有者。零值不可用,请用 New。
func (*Host) Attach ¶
func (h *Host) Attach(id string, since uint64) (*Attachment, error)
Attach 订阅一个会话,并原子地取回 since 之后的历史。
「原子」是关键:回放与订阅必须在同一把锁里完成,否则两者之间产生的输出 会两头都不落,用户看到的历史就缺了一段。
func (*Host) Close ¶
Close 显式关闭会话:整组 SIGTERM,宽限 termGrace 后 SIGKILL,并立即 把会话从列表里摘掉。
注意:摘除是同步的、杀进程的兜底是异步的——DELETE 请求不该为了等一个 赖着不走的进程而挂 2 秒。用户点了 ×,列表里就该立刻没有它。
type OpenOptions ¶
type OpenOptions struct {
BasePath string
BaseKind string
Shell string
Env []string
Cols int
Rows int
}
OpenOptions 是开会话的入参。Env 是**完整环境**,不会再追加 os.Environ()—— 这正是 spec §4.2 要绕开的那个坑(封存分支 service_unix.go:43 的写法)。
type Session ¶
type Session struct {
ID string
BasePath string
BaseKind string
Shell string
CreatedAt time.Time
Cols int
Rows int
Attached int
PID int
ExitCode *int
// Foreground 表示会话里当前有一个跑在前台的命令(前台进程组 ≠ shell 自己)。
//
// 为什么是 bool 而不是三态:读不到(shell 已退出、平台不支持)时结论是
// **false**——两种情形下「关掉它会打断什么」的答案都是「不会」,与真的空闲
// 同解。这与 PtySupported 那种「不知道」不是一回事,不要照抄那条纪律。
Foreground bool
BytesOut uint64
}
Session 是一个会话的**快照**,跨出锁之后可以自由持有。
ExitCode 用指针表达三态里的两态:nil = 还活着,非 nil = 已退出且这是退出码。 这条与项目里 Watchers / Live / Procs 同一纪律——绝不用 0 或 -1 冒充「不知道」。