Skip to content

Latest commit

 

History

History
839 lines (653 loc) · 80.7 KB

USER_GUIDE.md

File metadata and controls

839 lines (653 loc) · 80.7 KB

forge 用户指南

1. 启动、诊断与恢复

forge 默认启动 Block 后端并恢复最近一个可领取的窗口快照:

forge
forge ~/project
forge --working-directory ~/project
forge --mode vte --no-restore
forge --execute bash -lc 'cargo test'

--execute 后的参数原样作为 argv,不经过额外 shell 拆词。显式 cwd、--execute、--no-restore 和 --safe-mode 都不会意外领取普通恢复快照;execute/safe-mode 窗口也不发布会话快照。单独使用 --mode 只覆盖本窗口后端,仍可恢复窗口布局。

Block 历史保存失败的常驻提示中,Retry 会在加载失败时先重新读取文件。修复后重试会恢复并保存;如果重试仍失败,提示会再次出现。普通自动保存不会反复弹出同一错误。

Unified 恢复历史时会校验所有记录,但只在解码队列中保留最新 64 条;数量筛选完成后才应用输出字节上限,避免丢弃原本能保留的近期输出。

Unified 历史文件若版本不受支持、损坏或无法读取,pane 仍可使用,但不会删除或覆盖原文件,也不会保存该 pane 的新历史。常驻提示的工具提示包含文件位置和原因;请先修复或移走该历史文件,再重新打开 pane。仅修改磁盘文件后重试保存不会丢弃尚未恢复的内容。缺失的文件是正常新会话,仍可保存;合法的空历史与读取失败会分别处理。若旧文件因恢复数量或内存上限只载入一部分,原文件也会保留;请先备份,再缩减或移走该文件并重新打开 pane。

恢复窗口时,超出标签或拆分布局上限的原始快照会先移到同目录的 .corrupt-* 恢复副本,再保存当前工作区;这些副本沿用最多保留 8 份的既有清理策略,并非永久备份。如果移动失败,窗口会提示文件位置并暂停会话保存,原文件保持不变。请先备份该文件,解决存储问题后重新打开窗口;只有实际重新读取成功后才恢复写入。

恢复会话时,先前的活动标签只要保留下来就仍会被选中。若它因无效或超限布局被跳过,则选择其前方最近的保留标签;没有前方标签时选择第一个。

以下命令在 GTK 初始化前完成,可用于 SSH、TTY 和 CI:

forge --help
forge --version
forge --doctor
forge --doctor --json
forge --config-path
forge --init-config
forge --check-config
forge --check-config --json
forge --restore-config-backup
forge --print-default-config

--doctor 报告配置语义与权限、有效轮换备份、配置写锁、显示/input 环境、可选工具、AI provider/密钥存在性、workflow 与欢迎 Notebook 发现结果、远程 SSH 就绪度以及 ready/active 快照数量,但不输出快照中的目录、标签或命令,也不会探测任何网络 endpoint。使用独立配置:

forge --config ~/configs/work.toml
forge --check-config ~/configs/work.toml

自动配置目录必须是绝对路径:优先使用有效的 XDG_CONFIG_HOME,否则使用绝对 HOME 下的 .config,最后尝试 GLib 提供的绝对配置目录。无法确定时不会转向当前工作目录;配置、窗口及 Agent 会话的自动持久化暂停,已有文件保持不变。显式 --config / FORGE_CONFIG 仍可选择相对路径;显式 --check-config PATH 不依赖自动目录。

--check-config --json 的正常路径报告保留原有字段类型。仅在未指定路径、且自动目录无法确定时,错误报告的 path 与 exists 为 null(未知),valid 为 false、errors 为 1,并以失败状态退出。脚本应先检查退出状态及 valid,再读取路径字段;未知目录不能当作首次运行或文件不存在。--doctor 同样将无法检查的备份及会话数量报告为错误,而不是零。

安装版还提供隐私保护的支持归档工具:

forge-support-bundle ~/Desktop

它通过脱敏诊断模式收集权限/大小元数据、聚合计数、非敏感系统特征和选定环境变量是否存在,不打包配置正文、历史、会话、终端输出、剪贴板、API key、SSH 目标、主机名或本地路径,也不会发起网络请求。归档权限为 0600;发送给他人前仍应检查每个文件。

forge --safe-mode 完全跳过用户配置及 FORGE_* 外观/行为覆盖,使用内置 VTE 主题和默认快捷键;同时禁用配置重载、恢复、配置/会话持久化、历史、仓库探测、远程主机、通知、AI 和可执行 Notebook。它适合确认故障来自用户配置还是图形/终端环境,不能与 --mode 或 --execute 同时使用;即使同时给出 --config,该文件也不会被读取。

2. Shell 集成

Block 后端可在没有集成脚本时工作,但加载脚本后能通过 OSC 133/7 精确获取 prompt/command 边界、退出码和 cwd。无需查找安装路径:

# ~/.bashrc
[[ $TERM_PROGRAM == forge ]] && source <(forge --shell-integration bash)

# ~/.zshrc
[[ $TERM_PROGRAM == forge ]] && source <(forge --shell-integration zsh)

fish 和 PowerShell 对应 fish、pwsh。原生安装还会把四种脚本放到 ${prefix}/share/forge/shell-integration/。其他终端会忽略这些 OSC 序列。

Flatpak 的交互 shell 运行在宿主机,宿主 rc 不应直接引用沙箱内的 /app/share。bash/zsh 可在对应 rc 中使用 source <(flatpak run io.github.beamiter.forge --shell-integration bash);fish 使用 flatpak run io.github.beamiter.forge --shell-integration fish | source。 两种后端都会在读取 rc 前注入 TERM_PROGRAM=forge,因此可继续用该变量做条件保护。

3. 终端模式与 Pane

默认配置是:

terminal_mode = "block"
  • block 把命令保存为独立块,提供退出状态、耗时、筛选、跨块搜索、历史回填和 AI 上下文。
  • unified 使用一个持续存在的 VTE 滚屏,同时保留可信的命令分区、状态 badge、搜索、 有界输出快照与恢复;Kitty a=T 图片按 r=/c= 单元格覆盖显示,并随滚屏与重排定位。 缺失 OSC 133 D 时,只有确认 shell 已重获 PTY 前台的新 prompt 才会恢复该记录;记录标为 boundary_inferred / degraded,不伪造退出码、结束时刻或耗时。
  • vte 是传统终端,适合要求完整滚屏语义的 TUI 或兼容性排查。

Unified 运行中的分区元数据同时受 max_visible_blocks 与每 pane 128 MiB 估算内存上限约束(包含命令和 cwd 字符串容量),从最旧记录开始淘汰,最新记录始终保留;输出快照另受 4 MiB 总量限制。淘汰元数据会清理其书签和 badge,但不擦除 VTE 自身的滚屏文本。

Unified 的重启历史保留最近至多 64 个分区,命令、cwd 与输出合计最多 4 MiB,实际 JSON 文件最多 8 MiB(包括转义与元数据)。达到上限时先舍弃较旧输出,再舍弃较旧分区;保留下来的截断提示不会伪装成完整输出。

Kitty 支持刻意限定为 direct a=T 静态显示(i、c/r/C,PNG/RGB/RGBA)与 a=q 探针;a=t、I、crop/z/relative placement、delete/replacement 返回 ENOTSUP。 Unified 遵守这些单元格坐标;Block 保留既有“图片作为完成卡片附件”的 profile,不保证 c/r 原位坐标或 placement replacement,因此不能当作完整 Kitty placement 实现。

实验性 ASCII organism

Block pane 可以显式启用一个完全本地、无 LLM 的 ASCII organism:

ascii_organism_enabled = true

临时试用可设置 FORGE_ASCII_ORGANISM_ENABLED=1。Settings 的启停和动作等级会立即 作用于已打开的本地 Block / Unified pane;修改配置文件后使用 Reload Config,无需重建 pane。关闭会立即收起身体、卡片和该 pane 的动画定时器;重复启停不会重复挂接。它监听 Forge 从 OSC 133 边界捕获的真实 command start/finished 事件。生命体平时沿 live terminal surface 缓慢移动,命令运行时靠近输出区观察;用户上滚查看历史时,它缩成 sticky header 里的单行形态。PTY 真正接收键入、粘贴或进程控制键后,live body 会立即收起; 持续键入只延长约 900ms 的停笔窗口,结束后直接贴位回来,不播放奔跑过渡,避免 打断工作专注。Agent、纠错和命令面板的程序化写入不会伪装成真人输入。alternate screen 和放不下完整 sprite 的窄小 surface 会直接隐藏空间身体,结果仍保留在 prompt 上方的 inline widget。图层不参与 GTK 测量、不改变 PTY 行列、不可点击,也不向 PTY 注入 ANSI。传统 VTE pane 使用独立的中性伴随体,默认紧凑显示;命令面板中的 Expand VTE neutral companion / Collapse VTE neutral companion 可展开或收起它。 该形态不感知命令或 alternate screen,不显示命令反应,也不提供 live Say hello; Settings 中的离线预览仍可使用。

在可见的静息身体旁停留指针约 600ms,它会轻轻抬头回应约 2 秒;同一窗口的分屏共享 8 秒冷却。点击与拖选仍交给终端,身体不接管键盘或焦点。真实输入、命令开始、切 pane、 窗口失焦、全屏应用或几何变化会取消驻留;忙碌和错误守望不会被问候打断。Calm 只切换 静态姿态,Static 不显示空间身体。此互动不修改真实生命状态或记忆。

Settings 的 Organism Preview 可查看八种姿态、解释和本地 Say hello 示例,即使生命体 关闭也可预览。预览不运行命令、不写养成记忆;隐藏或关闭设置后不保留动画定时器。

命令面板的 Inspect ASCII companion 可查看当前 pane 的真实状态快照:姿态与原因、 命令是否还在运行及已用时间、最近反应、未解决的构建/恢复、成长天数与恢复次数,以及八个 有名称的状态刻度。刻度描述的是模拟生命体自身。查看不会改变生命状态、触发问候或写记忆, 也不会开启轮询和动画;重新打开即可刷新。可以在 [keybindings] 中按需设置 inspect_ascii_organism = "F10",默认不占用快捷键。快照不持有 pane,关掉终端后不会 留下 PTY。传统 VTE 显示能力说明,不会编造命令结果。人类命令与 Shell Agent 的输出节奏 都有对应的解释;“输出安静”明确仍是运行中,不代表完成或卡死。

感知只在内存中保留“不含内容”的 accepted-input/output-activity 脉冲,不记录 按键、剪贴板或输出文本。它会观察 build/test、检查非零退出,并在失败后成功或 git push 时作出克制反应;不执行任何命令,也不发送网络请求。连续状态与按 “本地日期 + 完整 Git 根路径” 隔离的失败、恢复耗时、间歇性翻转、构建时长、push 统计和八个三小时活动桶会私密地保存到 ${XDG_STATE_HOME:-~/.local/state}/forge/ascii-organism-native.json。状态文件有大小、 schema、权限和跨进程事务边界;损坏或未来版本会停用持久化而不会被默认值覆盖。 只有本机可验证的 Git checkout 会进入记忆,不保存命令文本或输出。若同一 repo 今天从首次失败到恢复的时间短于昨天,恢复后的 git push 会得到一句跨日反应。 为合并多窗口乱序完成的事件,文件仅保留至多 256 条、每个 repo/day 至多 64 条 不含命令内容的短期 transition ordering metadata,以及至多 512 个不含 PID/命令的 不透明去重 token;较旧条目会折叠回统计基线。迟于该有界排序窗口的全新事件仍计入 单调总数,但不会改写已经折叠的失败/恢复顺序。 活动桶只记本地墙钟时段里的 build/test 与 push 完成次数,不记命令、输出、时区或 UTC 偏移;事件创建时会把日期和时段一起冻结,因此夏令时跳变和事务队列延迟不会 重新解释历史。

事件之间它也活着:内在状态以约 100ms 的帧连续演化——清醒工作缓慢消耗能量, 启用 organism 的本地 Block pane 全部安静约一分钟后进入静息、能量回升(远程 与 VTE pane 不参与感知);精疲力竭时即使命令仍在跑也会强制打盹,能量在低位 自稳而不会归零。有人敲键盘时无聊下降、好奇上升,被冷落则相反;压力自然衰 减,心情向能量/信心/压力合成的目标缓动。多个 Block pane 共享同一颗心灵、一个 时钟和一份作息,身体数量不会加快生命节奏。该模拟只存在于内存,落盘仍只 发生在命令生命周期事件。

积累最近 28 天中至少三个完整本地日期、六个以上活动样本后,它会在活动足够集中 时学习一个连续九小时的惯常工作窗口;零散或双峰作息保持未学习,不强行归类。 惯常时段内清醒能量趋向较高目标,时段外则更容易安静休息,真正睡眠仍照常回能。 每个本窗口的工作 session 第一次由真人启动命令时会轻声问候(白天是「早。」, 晚间是「来了。」);跨午夜的夜班只算一次,Agent 命令和时段外命令不会消耗这句 问候。若同一命令还触发更具体的「回来了。」,repo 问候优先。样本不足时能量演化 完全保持原先规则。

它也会长期长大。全局记忆把跨 repo 的不同工作日与「一段失败被一次成功收束」的 恢复 episode 做成有界、去重的纯计数:少于 7 个工作日是 juvenile,之后是 adult; 至少 60 个工作日且经历 12 次恢复后成为 seasoned。阶段显示在 inline badge 中, 也直接留在身体表型上:juvenile 眼睛更圆、细小动作更快,adult 保持标准轮廓, seasoned 带一侧耳缺口、动作节拍更从容。每个阶段在同一姿态组中仍占用相同 包围盒,因此成长不会让安全尺寸判定忽隐忽现。成长只改变表达,不改变失败/成功 带来的状态量或姿态强度;seasoned 面对一次大的真人恢复仍保持完整庆祝,只把 「终于。」收成一句「嗯。」。最近工作日集合有 64 日排序窗口和 压缩游标,极端迟到的旧事件宁可不催长,也不会因 daily record 淘汰而重复长大。 旧 v1 记忆从仍可验证的日记录与翻转计数迁移为安全下界,不猜测已经遗失的历史。 渲染时,语义行为、连续内在状态量化出的身体语言、成长阶段与输出节奏是彼此独立 组合的四层上下文,而不是为每种排列另造一个持久状态。例如紧张仍能压耳、困倦 仍能卧下,同时保留 juvenile/seasoned 的表型;错误、恢复与 push 等规范姿态的 语义标记不会被装饰层遮掉。这个组合只发生在显示端,不新增记忆字段。

动效可以收敛:ascii_organism_motion = "full" | "calm" | "static"——calm 只在 行为边界换姿(无游走、无摆动、无帧交替、位移直接贴位),static 只保留 prompt 上方的 inline 卡片;未设置时跟随桌面动画偏好(系统关闭动画则自动 calm), 临时试用可设 FORGE_ASCII_ORGANISM_MOTION。驱动本身也克制:只有当前获焦、未进入 alternate screen 的 full pane 在活动时使用每秒至多十次的 glib 定时器(不强制 GTK 帧时钟 满速运转);其他 pane、calm、static 以及整窗安静一分钟后的 full 都降为约 0.9 秒 一次的心跳,隐藏 tab/pane 不会随数量线性叠加高频动画成本。焦点转移会立即刷新 新 owner,并安全地把它的下一拍重排回全速。

它分得清「陪主人」和「看 Agent 干活」:Shell Agent 提交的命令(在 CommandStart 处经身份校验)让它蹲到一旁静观,成功只得到无言的小幅认可——大庆祝、 「终于。」和「收好了。」只留给主人亲手敲的命令;Agent 的失败也不动摇主人的 信心、不触发敏感化。Agent 会话的粗粒度阶段(工作中/等审批/完成/离开)作为 不含内容的脉冲喂给社交需求与依恋——Agent 占用主人注意力越久,它越想念主人, Agent 离开后更可能坐到提示符旁守着。命令若失去结束标记,它以警示色调克制 说明,绝不当作成功。

真正闲下来时(无命令、无反应、无人敲键盘),行为由内部状态经效用打分自主 涌现:困了蜷在左下角睡觉(睡着会回能量,睡饱自然醒来做别的)、无聊且好奇时 四处踱步探索、想念主人时坐到提示符一侧守着;已选行为带保持计时和些许惯性, 不会每帧重掷。命令、键入或任何反应都会立即打断当前性情。

它现在会把一轮调试从失败陪到 push,而不只对单个事件做短暂反应。同一 repo/day 有一到两次尚未恢复的 build/test 失败时,反应结束后留下 [!];累计到三次及以上 则降成更安静的 [!!],不追加催促或语音。失败与卡住姿态只会守在当前输出边缘 以下的完整空白带;空间不够就隐藏 live sprite、只保留 inline 卡片,绝不会覆盖终端 文字。未知结果、普通命令和失败的 push 都不能抹掉这段未完成工作。

成功 build 会把失败守望转成提示符旁的 [ok],一直等到真正成功的 git push; 后续干净 build、普通命令、失败的 push 与 git push --dry-run/-n 都不会被误当成 收尾。若同一天已经发生至少三次失败→成功翻转,等待 push 的姿态会变成谨慎的 [?]:它只表示“今天值得再确认一次”,不会断言当前测试一定 flaky。新的 build 失败会重新进入 [!]/[!!],成功 push 或本地日期跨日才结束当日弧线。

离开 checkout 只暂停当前身体的守候;同一天回到该 repo、下一次 build/push 解析出 canonical root 后仍会从记忆恢复。同窗口里已经解析到完全相同 repo/day 的 pane 会 立即接力同一个类型化工作快照;临时侧目不会覆盖任何 [!]、[!!]、[ok] 或 [?] 守望。其他窗口在下一次语义命令刷新记忆时收敛。普通路径离开由原始 cwd 立即判断,嵌套 Git repo 则在下一次 build/push 重新解析 canonical root 时完成切换。 整条弧线直接复用已有的 open failure、recovered_pending_push 与翻转计数,不新增 持久化字段;能量跌到强制休息线以下时它仍会先睡,并在回升到带滞回的唤醒线后 回来守着。

内在状态也能直接从身体上读出来:能量低时先打盹、随即蜷起来睡着并停止游走, sticky 单行形态同步换成打盹字形;压力高时耳朵压平;无聊到顶会偶尔打哈欠、 游走占比提高。 卡片状态行只显示最多三个自然词(如 sleepy · tense · curious),完整八维数值移到 tooltip,避免日常界面长期暴露 E72 M62 … 这一类调试仪表盘。 行走有交替步态帧,观察输出越密集甩尾越快,庆祝会保留猫耳并眨星、push 后守着尾巴打盹。 同一姿态组内的所有动画帧共享包围盒,空间身体的 fail-closed 尺寸判定不会因 动画帧抖动;错误/庆祝等反应姿态保持规范形态,不被身体语言覆盖。 每次命令反应与跨 pane 侧目都从各自的规范首帧开始,不会继承闲逛时恰好落到的 全局动画相位;idle 游走本身仍连续,不会因卡片刷新重新起步。

空间身体不再瞬移:姿态切换时它以整格步进走过去(剩余距离的四分之一每帧、 至少一格,跨全屏约一秒,途中播放步态帧)。键入撤退与 alternate screen 都会 立即隐藏;键入期间帧循环也不会把它提前唤回。被隐藏后再出现是直接贴位,它从不 在看不见的地方走路。 命令运行和反应时的空间姿态也不再覆盖最新输出:它优先守在光标下一行开始的 空白带,并随光标下移一路跟下来(只取行号这一内容无关几何量);完整身体放不下 就隐藏 live sprite、保留 inline 卡片。姿态宽高、字体或 scrollbar gutter 改变时, 旧位置会失效并重新贴到安全点,不会在插值途中越过输出或滚动条。

同一窗口现在只有一具完整空间身体:它属于当前真正获焦的本地 Block pane;其他 pane 仍保留自己的 inline 事件卡和 sticky 微姿态,但不再各自游走。焦点落到搜索、 对话框、VTE/远程 pane,或窗口失活时,Block 的 live body 会撤下;传统 VTE 的 中性伴随体使用自己的焦点与显示条件。切回本地 Block 后先 重新测量再出现。切 tab、分屏关闭、zoom 和 alternate screen 都沿用同一弱引用 仲裁,不搬运 GTK widget,也不会让旧 pane 从 rmcup 恢复一个过期位置。 Notebook 切页会在 signal 当下先撤销旧 owner,待 GTK 提交新页后再认领,因此切换 间隙的旧页既不能以隐藏睡姿回能,也接不到本应属于新页的侧目脉冲。

后台本地 Block pane 若收到权威的非零退出状态,当前可见且空闲的空间身体会短暂 侧目;跨 pane 传递的只有“失败”这一类型化事实,不含命令、cwd、输出、退出码或 repo 身份,也不会抢焦点、弹窗或改写任一 pane 的 inline/sticky 记录。当前身体正 在键入、守望、反应、任一 repo 调试守望、alternate screen、Static 模式或完整姿态 放不下时,这次侧目直接丢弃而不排队,因此切焦点后不会补演过期失败。

长命令它会陪跑:跑过十秒的命令,卡片状态里出现「· 2m 30s in」的陪跑时长 (每拍最多更新一次,只是文本);守望超过一分钟,它从警觉守望换成卧姿的 打盹式守望——还在看,只是眯着眼。成功构建的墙钟耗时会以饱和聚合的形式 (总和+次数两个纯标量,单次封顶六小时,不存命令文本)计入该 repo 的日记录; 累计三次以上的历史样本形成基线,当前构建本身不会稀释比较;成功构建若比此前 平时慢一倍以上或快一倍以上(且 绝对差超过十秒),description 里静静补一句 slower/quicker than usual here—— 不升级姿态、不打断。陪跑时长以十秒为步进更新,避免朗读辅助技术逐秒播报。

运行中的观察还会从纯 output-activity 脉冲时间推导粗粒度节奏:滚动的约 1.2 秒 窗口内出现至少三个脉冲时专注跟看,约三秒没有新脉冲时安静等待(包括启动后始终 没有输出的命令);沉寂后输出恢复,只短暂 抬头约 0.9 秒再回到当下节奏。既有的长命令守望超过一分钟后仍会进入卧姿 WatchSettled。它不读取字节、行内容或 ANSI,也不把“安静”猜成成功、失败或某个 构建阶段;权威的 command finished 事件仍是唯一结果来源。节奏只存在于内存, 只影响身体语言和动画拍子,不进入 repo 记忆或卡片事实。

反应强度是历史的函数而非刺激的常函数:同一 repo 当日每多一次干净通过, 兴奋度按 1/(1+已有通过次数/4) 衰减,先安静下来、随后不再说话;长串全绿后的第一次 失败反而刺痛更深。反复失败后的恢复始终全力庆祝。记忆里从未见过的 checkout 会让它怯生(更安静、信心下压),积累一周以上日记录的老仓库在切回时得到一句 「回来了。」。会话内任意命令连续三次非零退出后,它坐到一旁、不再逐次开口。 纠错卡片的接受/关闭只作为不含文本的脉冲传入:被采纳的修正在命令成功后得到 一次无言的小幅认同,连续关闭则让它学会闭嘴。上滚时的 sticky 单行形态也会用 定宽五字符的微姿态(竖耳/压耳/星点/打盹)低频反映当前行为。以上全部派生自 内容无关观察;新增落盘信息只有上述有界计数、聚合和时段桶,仍不包含命令或输出。

熟悉 repo 后,它也会形成不打扰工作的“领地习惯”。显示层以已验证 canonical repo identity 的进程内稳定哈希选择偏爱的窝边与行走路线;陌生 checkout 的第一次反应 安定后,若没有更重要的失败/恢复守望,会做一次很短的探索;冲突时直接放弃而不 延迟补演。哈希只在本次进程中用于布局,不显示路径、不传入 reducer、不新增落盘字段;repo 无法验证或身份切换中时使用中性的安全位置,几何 不足则照常 fail closed。离开 checkout 仍按既有规则释放当前守候,不把一个仓库的 领地带到另一个。

短时间内多个表达同时到来时,一份窗口/session 内的注意力预算只放行最重要的可选 语音或低优先级动态表达:失败与未完成守望优先于恢复闭环和 push 收尾,随后是长 命令变化,最后才是问候与低优先级 insight。持久的 [!]/[!!]/[ok]/[?] 事实不会因仲裁丢失;已放行的表达占用一段共享 focus window,并为自己的类别留下 冷却。期间被压住的低优先级表达直接丢弃,不排队补演。新输入、alternate screen 和尺寸安全仍可立即撤下所有表达,注意力预算不能越过这些边界。

同一天内若已至少三次出现失败→成功翻转,而当前只积着一次失败便恢复,它会轻声 提示「像是偶发的。」并把姿态限制在普通庆祝;Agent 触发时保持无言。它不会把 疑似 flaky 的测试表现成更大的胜利,也不会凭该提示提高反应强度。

反应停留也不再统一占住八秒:安静通过约 1.8 秒、普通通过约 2.5 秒、首次错误约 5 秒、大恢复约 7 秒,连续错误旁坐约 10 秒;任何新输入或命令仍会立即打断。 因此快速测试循环不会让轻微成功长期霸占空间,而真正需要注意的失败会多陪一会。

几个关键行为边界在 full 模式下会用四个固定包围盒帧连接:即时错误反应 坐定为失败守望,庆祝收束为恢复或谨慎守望,长时间卧姿守望被成功唤起进入庆祝, 恢复守望在 push 收尾后卧下休息。过渡帧只解释“怎么到达”目标姿态,不改变 reducer 已确定的事实、反应优先级或停留时长;新事件可以立即取消旧过渡并从自己的规范 首帧开始。完整过渡身体放不下仍隐藏 live sprite。calm 直接切到目标姿态,static 继续只显示 inline 卡片;键入撤退和 alternate-screen yield 在 full 下也始终立即 执行,不等待过渡播完。

两个后端共享输入路由、字体/主题、cwd、进程检查和关闭清理。分屏继承当前 pane 的后端:Block 创建 Block sibling,VTE 创建 VTE sibling;两种 sibling 都可继续嵌套,也可在恢复的混合布局中共存。这避免隐藏 PTY,并让分屏行为不受随后修改的默认后端设置影响。

操作 快捷键
左右 / 上下分屏 Ctrl+Shift+E / Ctrl+Shift+D
方向聚焦 Ctrl+Alt+方向键
调整大小 Ctrl+Alt+Shift+方向键
放大当前 Pane Ctrl+Shift+Z
Pane 移到新标签 Ctrl+Shift+!
关闭当前 Pane 或标签 Ctrl+Shift+W

关闭 pane、标签、多个选中标签或窗口时,forge 会扫描所有后端的真实 PTY 和前台进程;存在运行中任务时先给出统一确认。缩放的 pane 会先恢复 pane tree 再关闭,避免漏掉隐藏 sibling。

分屏布局恢复仍建议与命令自身的持久化方案配合使用,尤其是 SSH/TUI 长任务。

4. 标签页与窗口恢复

操作 快捷键
新建标签 Ctrl+Shift+T
下一个 / 上一个标签 Ctrl+Tab / Ctrl+Shift+Tab
标签 1 到 8 / 最后一个 Ctrl+1…Ctrl+8 / Ctrl+9
过滤标签 Ctrl+Shift+L
标签栏位置 Ctrl+Alt+B

标签支持按落点前后拖放排序、双击重命名、固定、标记、复制和右键菜单。后台标签页有输出时显示活动标记,响铃(BEL)时显示响铃标记;窗口未激活时,当前标签页的响铃同样会标记,并弹出一条以标签名为标题的 “Bell from <程序>” 桌面通知(每个面板 30 秒内至多一条),窗口重新激活时清除。codex 默认在回合结束时响铃;Claude Code 需把 preferredNotifChannel 设为 terminal_bell(或 ghostty,发送 forge 直接显示的 OSC 777 通知),见 config.toml.example。程序退出时发送空标题(claude、codex 都会),标签恢复为按工作目录生成的默认名;手动重命名过的标签不受影响。过滤框固定显示在侧栏的 Tabs 视图中;Ctrl+Shift+L 会自动打开侧栏、切换到 Tabs 并聚焦过滤框。侧栏在 Tabs 与 Files 之间切换;开关、宽度和视图会持久化。

每个进程维护独立 active 快照。正常关闭后才原子发布为 ready;并发窗口不会读取或覆盖彼此 active 状态。后续启动逐个领取最近快照,确认 owner PID 已结束后才回收崩溃遗留的 active 快照,最多保留 32 个 ready 快照。旧版 tabs.state 会在首次启动时迁移。

底部状态栏中的长路径或 Git 信息会在中间省略以适应窗口宽度,悬停可查看完整状态文本。网格尺寸、退出状态和标签计数保持正常显示。

5. 搜索与 Block 操作

Ctrl+Shift+F 打开当前标签搜索:普通文本不区分大小写,/expression/ 使用正则;Enter/Shift+Enter 前后跳转,Escape 关闭。清空输入立即清除 VTE 和 Block 高亮。查询上限为 8 KiB;增量搜索最多检查 4 MiB,并以 12 ms 为 surface 间的停止目标,最多记录 10,000 个命中。达到任一边界时状态栏会显示结果不完整,请缩小关键词。可能产生零宽命中的正则会明确拒绝,避免游标与高亮失去同步。全屏程序(alternate screen)占据 pane 时,搜索只针对正在显示的 live 终端,不统计被隐藏的已完成块。 命令运行期间,live 终端的命中数取自它自己的缓冲区(scrollback 加屏幕),原生 VTE 游标仍有同一行多次匹配和软换行跳转限制;不能把增量计数视为逐字范围证明。

保留文本精确预览

搜索栏的 Preview 打开独立的只读窗口,冻结当前 pane 已完成记录中仍然保留的 prompt、command 和 output。它不读取 live VTE、不跳转原终端、不替换现有 Find。 “Preview: 2 of 3”只计算该快照中可搜索的保留文本;缺失的 prompt/output 数量会显示, 部分保留的输出(可能只有尾部或前缀)会明确标注。它不是完整 scrollback 的总数。

在预览自己的输入框修改关键词;Regex 使用 Rust regex 语义。默认不区分大小写(正则内联 flags 遵循 Rust 语义), 逐逻辑行、逐字段、非重叠匹配;不能跨硬换行或字段。软换行和窗口缩放不会改变快照。 零宽/可能匹配空串、lookaround 和 backreference 模式会拒绝;消耗字符的 ^word$ 等模式可用。控制字符和双向文本控制符显示为转义,搜索也针对显示后的同一份文本, 不另行规范化 Unicode。Previous/Next 或 Shift+Enter/Enter 在同一快照循环导航; 当前命中使用 TextView 标记,不创建原生终端 selection 或取得 PRIMARY。

快照不随终端输出刷新;关闭再打开可重新捕获。原 pane 被移除或窗口关闭后,不会把旧结果 用于别的 pane。查询超过 8 KiB、保留原文或转换后的显示文本超过各自 1 MiB、字段超过 4096、单逻辑行超过 64 KiB、命中超过 10,000 或扫描触及时间目标时,请求整体拒绝,不展示部分总数或沿用旧命中。 扫描在后台单 worker 执行;100 ms 是协作检查目标,并不是单次正则编译/长行匹配的硬实时上限。 详见 预览范围与验收。

Block 功能 快捷键
命令历史面板 Ctrl+Shift+H
跨块行搜索 Ctrl+Shift+G
跳到首个失败块 / 最早块 Ctrl+Shift+X / Ctrl+Shift+N
workflow Ctrl+Shift+M
AI 分析选中块 Ctrl+Shift+Q
Shell Agent Ctrl+Alt+G
全选 / 回填 / 清空 Ctrl+Shift+A / Ctrl+Shift+I / Ctrl+Shift+K

跨块搜索的 Aa、.*、W 分别控制区分大小写、正则和 Unicode 整词匹配,亦可用 Ctrl+I、Ctrl+R、Ctrl+W 切换。三个选项可组合,结果列表和跳转后的 VTE 高亮不会 使用不同的查询语义。范围下拉框的 All / Cmd / Out 分别搜索全部文本、仅命令或仅输出; Ctrl+O 可循环切换,且范围在 500 条命中上限之前应用。Failed 只显示真正失败的块(不把用户 主动中断算失败),Slow 只显示耗时至少 1 秒的块;筛选先于 500 条上限应用并可组合。查询为空时,启用任一筛选会为每个 符合条件、且在当前范围有内容的保留块显示一条可定位代表结果,可直接浏览失败或慢块。 搜索状态会显示 当前位置 of 总数;↑/↓ 循环移动,Home/End 跳到首尾, PageUp/PageDown 每次移动十条。列表会跟随选择滚动,但焦点仍留在查询框。 Enter 定位后关闭面板;Shift+Enter 成功定位实时终端结果后保持面板并自动选中下一条。 快照结果仍进入快照窗口,已经失效的结果不会关闭或前进。 再次打开会恢复本进程内上次有效的查询、匹配选项、范围及 Failed/Slow/Bookmarked/Background 筛选(不会写入配置或会话快照);Ctrl+U 只清空查询,Reset 或 Ctrl+Shift+U 一次恢复 查询、匹配开关、范围及四个 元数据筛选的默认值。超过 8 KiB 的无效查询不会进入这份内存;鼠标修改控件后焦点会自动回到查询框,可直接继续输入。 打开期间会以 500 ms 的轻量版本探针感知新完成块、retention 轮换与 bookmark revision,再防抖 更新结果;仍存在的 稳定命中保持选中,探针本身不复制命令或输出文本。 Block Search 3.8 在该命中已被淘汰时回退到最接近的原排名,避免刷新后跳到列表顶部;主动修改 查询、匹配选项或范围仍会明确从第一项重新开始。按 F5 可立即重建当前索引而不改变查询意图 或选择锚点,手动刷新同时同步自动版本探针,避免重复工作。 Block Search 3.9 在标题栏提供可点击的刷新按钮;它与裸 F5 触发同一个刷新动作:同步版本 探针、取消待执行的防抖刷新并保留当前选择,最后把焦点还给查询框。带 Ctrl、Shift、Alt、Super、Hyper 或 Meta 的 F5 不会被面板截获,仍继续传播。 按钮向辅助技术公布完整的“Refresh block search results”动作名称及 F5 快捷键。一次物理按下 F5 到释放期间最多刷新一次,长按自动重复不会反复重建;若最初带修饰键,保持 F5 时松开修饰键 也不会把同一次按键重新解释为裸 F5 刷新。窗口失焦会清除 latch,避免 GTK 遗漏 release 后永久 抑制后续刷新。 Block Search 4.0 只在标题栏保留 Refresh / Reset,并把匹配与范围、元数据筛选拆成两行紧凑 工具栏;工具栏带自动水平 overflow,窄窗或大字体下可滚动访问超宽控件,并保留稳定 Tab 顺序。窗口 Capture 按 hardware keycode 把 block:search opener 的 held 状态传给 dialog fallback:一次物理按键只切换一次,release 前 的 repeat 只消费,既不会闪关,也不会在刚关闭后重开;中途松开 chord 修饰键也不会把 repeat 写入查询框,窗口失活会清理丢失 release 的状态。 手动刷新先显示并以中等优先级向辅助技术播报 Refreshing blocks…;首个 frame tick 只允许状态 完成绘制,下一 tick 才同步重建。新查询、筛选或再次刷新会取消旧 callback,选择锚点和立即回到 查询框的焦点语义不变。 Block Search 4.1 新增 Background 元数据筛选。传统 Block 以后台块没有命令来分类,Unified 以记录的显式 background 字段分类;显示与筛选时其命令、退出码和耗时都归一为空,因此 Background 与 Failed、精确退出码、Slow、最短/最长耗时互斥,遗留矛盾字段也不会改变这一点。空查询配合 Cmd 不产生结果;All / Out 只使用真实保留输出的首个非空行,没有快照或输出为空时不会 合成占位结果。筛选与范围继续在 500 条上限之前执行。该开关参与进程内记忆、关闭/重开和 Reset。 Cross Block Search 的关闭动画期间仍由当前 dialog 占用唯一 slot;其自身 closed 到达后才释放, 快速关闭、松键、再按打开不会让旧回调清除新面板。 Block Search 4.2 新增 Bookmarked 元数据筛选。它与 Failed、Slow、Background 按 AND 组合,筛选与范围都在 500 条上限之前执行;空查询也可浏览当前 pane 的书签。每个结果行都显示 ☆ / ★ 切换按钮,或在选中结果上按 Ctrl+Shift+B;一次物理按键只切换一次,长按和中途 松开修饰键不会反复切换或把 b 写进查询框。Block 卡片星标、CSS、Bookmarked 卡片筛选和搜索 结果使用同一集中状态,Unified 结果也能创建书签。书签集合只存在于当前 pane 的运行期内,不会 写入配置、历史或 session restore;Reset 只关闭 Bookmarked 搜索筛选而不删除集合。打开的面板 通过 bookmark revision 自动刷新;Unified 只有在真实记录被 retention 淘汰时才清理对应 id, 输出快照或 chrome marker 淘汰不会丢失书签。

选择语义与 anvil 对齐:

  • Ctrl+Up 从最新块进入选择;普通 Up/Down 移动 active edge,Shift+Up/Down 扩展范围。
  • Enter 或 Ctrl+Shift+I 按终端顺序回填所有选中命令,不自动执行;Escape 清除选择。
  • Ctrl+Enter(或右键 Re-run Command)重跑单个选中块的命令。这是 Block 模式唯一会 自行发送 Enter 的路径,条件很窄:只针对本 pane 中用户自己已经运行过的单行命令, 提示符必须空闲、无未提交输入、无待处理 typeahead;多选、background 块和会被截断为首行的 多行命令一律只回填不执行。模型给出的候选(AI、Agent、命令面板 ?)仍然只能 Insert for review。
  • alt-screen 程序运行期间,Ctrl+Up 不进入块选择、Delete 不删除隐藏块;进入 alt-screen 会清除既有块选择,避免快捷键作用在看不见的卡片上。
  • alt-screen 程序沿用运行中命令的网格:卡片只去掉装饰,边距与内边距不变,因此进入/离开 alt-screen 不会让程序收到 SIGWINCH(codex 的 Ctrl+T 浮层不再触发整段记录重放)。鼠标 程序的滚轮上报按滚动量累计为整格(触控板像素增量按 10 像素一格换算,单个事件最多 10 格), 并使用程序请求的编码(SGR/urxvt/UTF-8/旧式)。程序未关闭鼠标上报就退出时,命令结束与下一个 提示符会清除鼠标状态。
  • Delete 删除整个选区,一次按键即可移除用 Shift+Up/Down 建立的整段范围;命令面板中的 Undo removing blocks 把它们放回按 id 该在的位置,因此期间新跑的命令不会把恢复的块挤到 最前面。撤销槽是单级的:删除和清空共用它,新的一次移除会替换上一次。
  • 清空后的 Toast 提供 Undo,也可用命令面板 Undo removing blocks;恢复会合并仍保留的旧书签和多选状态。空 Pane 重复清空不会覆盖撤销槽,全屏程序占用 Pane 或历史容量不足时会保留撤销并提示重试。
  • Show only failed blocks / Show only slow blocks(≥1s)/ Show only bookmarked blocks 把块流收窄到匹配的卡片:不匹配的被隐藏且不再占据虚拟画布高度,Up/Down 选择会跳过它们, Ctrl+Shift+A 只选中可见的,过滤期间新完成且不匹配的命令也不会出现。Show all blocks 恢复 全部(没有过滤时它保持原来的「跳到最早的块」含义)。被信号停止的命令不计入 failed。 逐个跳转仍由 Ctrl+Shift+X 和书签跳转负责。
  • Collapse all blocks / Expand all blocks 一次收起或展开全部完成块的输出, Collapse or expand block 只作用于选中块(没有选中时作用于最新块)。折叠会同时缩小该块在 虚拟画布上的高度,因此滚动条长度与实际内容一致。这三个动作和 Undo 一样默认不占快捷键, 可在 [keybindings] 中绑定;折叠状态目前不跨重启保存。
  • Ctrl+Shift+B 收藏 active 块,Ctrl+, / Ctrl+. 在收藏块之间跳转。
  • 多选右键可批量复制命令、输出、完整块或回填命令;复制按界面顺序合并。
  • 长块提供顶部/底部导航与 sticky header,后台异步输出使用独立 Block 样式。
  • 块内输出过滤 Alt+Shift+F 打开后,Escape 或再次 Alt+Shift+F 可关闭:查询文本保留, 焦点交还实时提示符。
  • 历史恢复和撤销清空重建出来的块与新块拥有完全相同的右键菜单。
  • 在块内拖选文本后键盘焦点会留在那张卡片上,Block 快捷键仍然全部可用:方向键、 PageUp/PageDown、Home/End、Ctrl+Up、书签跳转、Alt+Shift+F 都照常工作。 有选中块时 Enter/Ctrl+Enter/Delete/Escape 按卡片提示条执行;没有选中块时 它们保持"把焦点交还提示符"的原意。普通打字始终把焦点带回提示符, 块内过滤输入框和弹出菜单内的按键归它们自己。命令(例如 claude、codex、kimi)运行期间, 这个把焦点带回来的按键也会照常交给程序(经实时终端自己的输入法,不会丢拼音首字母), 没有被 Block 占用的 Ctrl/Alt 组合键同样会送达程序;停在空闲提示符时它只负责交还焦点。 运行中的 Ctrl+C/Ctrl+D 兜底在焦点位于过滤框、历史面板搜索框等文本输入框时不再生效, 这些键归输入框自己(复制等)。
  • 命令运行期间仍有选中块时,Up/Down/Delete 让给程序(顺带清除选择),claude 的权限菜单 可以直接用方向键操作;Enter 仍被选择占用并响铃,但同时清除选择,下一次 Enter 就交给 程序;Escape 仍只取消选择,不会误中断 Agent。点击卡片标题栏上的按钮(复制输出、重跑、 折叠等)只执行按钮本身,不再顺带选中卡片。
  • Ctrl+单击 与右键菜单的 Open Link 同时识别纯文本 URL 与 OSC 8 超链接(claude 把 “Security guide”这类带标签的链接写成 OSC 8),只打开 http/https 目标;悬停在 OSC 8 链接上 时提示框显示真实目标。
  • 把文件或文件夹拖进 pane 会插入经过 shell 引号处理的路径(末尾一个空格,不回车)。任何 存在的本地路径都可以,不再只限图片;Block pane 以粘贴方式发送,程序开启了括号粘贴 (DECSET 2004)时带粘贴边界,与 Ctrl+Shift+V 一致。含控制字符或双向混淆字符的路径仍会被 拒绝(“Drop rejected: …”)。
  • 完成块同时受 max_visible_blocks 和每 pane 128 MiB 估算内存预算约束;预算包含 ANSI 原文、重复显示副本、VTE/控件与图片,超限时从最旧块开始淘汰,最新块始终保留。每个完成 VTE 最多保留 1,048,576 个 cells(最多 4096 列),因此极端长输出只在界面中保留有界终端窗口;这一几何裁剪不会再额外影响复制/导出中已捕获的文本(最多 8 MiB)。命令结束时,带纵向光标移动或滚动区域的输出(codex 这类内联 TUI、top、多行进度条)按子进程最后一次收到的终端尺寸重放:内联 TUI 插到视口上方的历史完整保留在卡片与复制/查找文本中,原地重绘的循环收敛为最后一帧。捕获超过 8 MiB 丢掉开头、或重放保留的历史超出约 200 万个 cells 时,卡片标题栏显示暗色的 “Earlier output not retained”;普通行输出超出文本重放预算(约 100 万个 cells)而丢掉结尾时显示 “Output text truncated”,两者同时发生时显示 “Output only partly retained”。这条提示随块数据保存,撤销、恢复和重新加载历史后仍然显示。Block Kitty 图片每块最多 64 张;Unified 图片使用同样的 16 MiB/64-placement 上限,超出可见网格的几何会明确拒绝而非静默缩放。

命令运行中或 alt-screen TUI 活跃时,Enter 和应用所需按键继续发送给前台进程,不会误触发旧块回填。

命令运行超过约 2 秒后,跟随底部时 pane 右上角出现一枚紧凑的运行胶囊:▶ 命令 用时, 计时每秒推进,并带一键 Stop。实时卡片的顶部一旦到了胶囊下面(codex、kimi 这类内联 Agent 把卡片长到整页高),胶囊就隐去,不会盖住程序以为自己拥有的前几行;这时用实时终端里的 Ctrl+C 中断。滚动到历史中时整宽运行状态条立即出现(此时实时卡片已不可见),alt-screen 程序活跃时让位;最小化后状态条缩成右侧的一个按钮。瞬时命令不会让它闪现。拖动滚动条、 查找跳转、书签或面板跳转离开底部哪怕不到一张卡片高,也会停止跟随,不会被下一帧输出拉回 底部。Stop、跳到最新与卡片标题栏上的按钮被点击后不抢键盘焦点:之后的按键仍然交给程序, Enter/空格不会再按一次 Stop。

退出状态区分「失败」与「被停止」:130(SIGINT,包括 Ctrl+C 和状态条的 Stop)、 141(SIGPIPE)和 143(SIGTERM)显示为中性的 ⊘ 卡片与 exit:N · interrupted 徽章, 不参与滚动条失败标记、Ctrl+Shift+X 失败跳转和 Failed 过滤;原始退出码在徽章、导出和历史里 完整保留,因此按精确 exit code 过滤仍能找到它们。Ctrl+Z 挂起的 148(SIGTSTP)同样是中性 卡片,徽章为 exit:148 · suspended,提示用 fg 恢复。SIGSEGV、SIGABRT、SIGQUIT、SIGKILL 这类真正的故障仍然是红色失败。

6. 统一命令面板、历史与 workflow

Ctrl+Shift+P 打开的面板统一模糊搜索四类来源:

前缀 来源 接受后的行为
> 应用动作与当前快捷键 执行动作
@ JSONL 命令历史 写入编辑行,不提交
: YAML/TOML workflow 填参数后写入编辑行,不提交
? 自然语言命令请求 交给 AI 生成候选,先审阅

JSONL 历史默认位于 ${XDG_STATE_HOME:-~/.local/state}/forge/history.jsonl,只保存 command、cwd、exit code 和完成时间,不保存终端输出。文件权限为 0600,重复命令按最新记录展示,损坏或超限记录会跳过,文件会按上限压缩。Ctrl+Shift+H 面板最多创建最近 500 行,即使磁盘保留上限更高;状态行会明确标出显示边界。

用户 workflow 放在 ~/.config/forge/workflows/,支持 .toml、.yaml、.yml;也可用 FORGE_WORKFLOW_DIR 增加以路径列表表示的目录。搜索顺序为:用户配置目录 → FORGE_WORKFLOW_DIR → 用户 data 目录 → 默认安装兼容层 ~/.local/share(仅当它与 user data 不同时)→ 各系统 data 目录 → 源码树示例;去重按名字且先到先得,因此用户定义优先于已安装示例,同名项不会被示例覆盖。用户配置目录解析不到绝对路径时(例如 HOME 未设置)该层直接跳过,不会相对当前工作目录解析成 ./.config/forge/workflows。

格式与加载器与 anvil、ember、frost 共用(jterm_core::workflows),同一个文件在四个终端里含义相同。字段类型必须正确,类型不符会拒绝整份文件而不是抹掉坏值后照常加载:default = 3000(忘了加引号的端口)、tags = ["net", 1]、缺 name 的 [[args]]、参数名带首尾空格、命令模板为空或含不可见 / 双向控制字符,都属于此类。被跳过的文件会在日志里留下 workflows: skipping <路径>: <原因>(超限、符号链接、非 UTF-8、解析失败同理),forge --doctor 的 workflow 计数使用同一套遍历,因此 doctor 与面板不会对「哪些文件算候选」给出不同答案。

安装包附带 feature branch、大文件查找、交互式 rebase、SSH 本地端口转发、Docker 日志跟随和端口进程终止示例。所有示例都只生成可编辑的单行命令;选中后不会自动执行,其中会结束进程或建立长连接的模板仍须由用户逐字审阅。

TOML 示例:

name = "Deploy"
description = "Deploy a branch"
command = "deploy --branch {branch} --env {env}"
tags = ["release"]

[[args]]
name = "branch"
default = "main"

[[args]]
name = "env"
# 没有 default:这个参数必须填。留空或只填空白时插入会被拒绝并报
# missing values: env,而不是把空字符串替换进模板。

模板支持 {name} 与共享格式的 {{name}} 两种 placeholder,占位符名两侧的空格会被忽略({{ service }} 等同于 {{service}});{{ }} 是字面花括号转义,未闭合的 {{ 原样保留(awk '{{print $1}' file 不会被改写)。零参数 workflow 也走同一条渲染路径,因此转义在任何 workflow 上都成立。

没有声明 default 的参数不能留空。 留空或只填空白时插入被拒绝并报 missing values: <名字>,参数对话框在按 Insert 之前就用 “Still needs a value: …” 列出仍然空着的行;kill -9 {pid} 在 Pid 一栏没填时不会插入 kill -9 。声明了 default 的参数(包括 default = "")仍可渲染成空值——「空值有没有意义」由文件说了算:清空一个有默认值的字段是一次有意的空值,清空一个没有默认值的字段是缺值。生成内容始终只进入当前 pane 的编辑行。为保证“只插入、不提交”,history、workflow、文件路径和 AI 候选只接受不含 CR、LF、NUL 或其他终端控制字符的单行文本;不安全条目会被拒绝并提示,而不会写入 PTY。

7. 可执行 Notebook

.jtnb.md 是普通 Markdown,其中 bash/sh/zsh/fish/pwsh/powershell/shell 或无标签 fence 可执行。双击文件树中的 Notebook 打开;内置 quick start 可在命令面板搜索 Open welcome & quick start notebook。

  • 每个 cell 可单独 Run/Stop,也可 Run All/Stop All。
  • stdout 与 stderr 分开显示,并保留 exit status;单 cell 合计输出有 256 KiB 上限。
  • 显式 shell fence 使用对应解释器;shell 和无标签 fence 使用 forge 的配置 shell argv。
  • 非 shell fence 只展示,不执行。
  • cell 在独立进程组运行,停止、Stop All 或关闭对话框会清理完整进程组。
  • 命令不会注入当前终端,也不会绕过 Notebook 自己的运行按钮;安全模式禁用执行。

安装资产位于 ${prefix}/share/forge/notebooks/;Flatpak 中是 /app/share/forge/notebooks/。

8. 文件树

侧栏 Files 页以当前标签 cwd 为根:双击目录展开/折叠;双击普通文件把 shell 引号保护后的路径插入编辑行,不自动执行;双击 .jtnb.md 打开 Notebook。向上按钮进入父目录,主页按钮回到当前终端 cwd。Block 走自管 PTY 输入,VTE 走 VTE child input。

点击 Files 路径标题可打开绝对路径输入和祖先目录按钮。长目录名会在中间省略,避免挤出 Open/Cancel;悬停查看完整显示名称,点击仍跳转到原始完整路径。目录层级较深时,祖先列表在对话框内滚动,路径输入、错误提示和 Open/Cancel 固定可见;键盘聚焦会滚动到对应按钮,手动滚动后静置不会自动跳回。

9. Flatpak 与桌面安装

Flatpak 应用 ID 是 io.github.beamiter.forge。打包版本通过 flatpak-spawn --host 启动宿主 Shell、SSH、Git、curl 和通知工具,避免命令误跑在一次性应用沙箱;因此 forge Flatpak 本身不是命令隔离边界。

flatpak run io.github.beamiter.forge --doctor
flatpak run io.github.beamiter.forge

文件树需要宿主文件系统权限。AI 密钥可通过可信启动器、显式 Flatpak override 或 sandbox 内可见的 owner-only 独立文件提供。完整权限说明见 docs/FLATPAK.md。

10. 远程会话与容器

远程主机严格按用户配置启用。配置文件没有 remote_hosts 键、显式写成 remote_hosts = [],或配置加载失败时,主机选择器都保持为空;forge 不会注入地址、用户名或容器名。下面的 SSH/容器片段只是可复制模板:端口写在 ssh_args 里,不能写成 host = "box:22";登录名写在 user 里,不能写成 host = "root@box"。

设置面板(Ctrl+Shift+O → Remote Hosts)可以添加/编辑/删除主机:铅笔图标用同一个对话框打开已保存的条目,面板没有控件的进阶字段(ssh_args、session、remote_shell、login_shell、multiplex、deploy_artifact)在编辑时原样保留,要改这些仍然直接编辑配置:

[[remote_hosts]]
name = "dev"
host = "dev.example.com"
user = "alice"
remote_shell = "jsh"
session = "dev-main"
ssh_args = ["-p", "2222"]
login_shell = true
multiplex = true

Ctrl+Shift+S 打开主机选择器。连接复用由 OpenSSH ControlMaster 完成,异常断开按上限退避重连;用户正常退出不会重连。

Files 侧边栏顶部也可以直接选择 ssh: 名称 / docker: 名称 浏览目标文件系统;选择器旁的终端按钮可立即进入该 profile。本地位置会精确在当前文件树根目录新开标签,远端位置从 profile 的默认目录启动(远端启动器没有通用的“指定 cwd”契约)。连接前的 home 探测不会阻塞 GTK;失败会显示原因并回到 Local,重新选择即可重试。配置增删、编辑或重排后,Forge 只按完整 profile 身份保留/重映射已经打开的远端树和文件剪贴板;目标身份不再唯一可证时会清理旧状态,绝不会让同一个数字索引悄悄指向另一台机器。若新建、重命名或删除确认框打开期间又切换了根目录/目标,旧操作会要求重新打开,不会把旧绝对路径交给新的后端。

直接在终端执行交互式 ssh [email protected] -p 22 也会自动进入对应远端文件树。这个便利功能覆盖 Block、Unified 和 VTE,但它只通过 jterm_core::process::observed_ssh_command 读取 /proc 中真实前台进程树(也能识别来源验证通过的 jsh SSH 升级 launcher),不信任终端输出或 OSC 133 的命令字符串。Forge 会优先复用唯一匹配的已保存 profile;没有唯一匹配时创建仅驻留内存、在位置选择器中标为 temporary 的 SSH 目标。显式 -S / ControlPath 及 jsh 派生的复用 socket 只进入不可变的执行快照,不参与 saved/temporary 身份和唯一性判断,并贯穿目录扫描、文件操作、剪贴板和传输;同一目标的两种表示也按同一文件系统处理,不会误走远端到远端 relay。后台 home 探测成功之前,当前文件树不会被清空或切走;完成时还会复核 SSH 仍在同一标签和焦点代际运行、自动跟随 token、配置身份、用户导航及文件操作 generation。失败通知会在点击重试时重新检查实时进程和 socket;不支持安全复用的参数可跳到 Files profile 选择器。退出 SSH 后远端树保持在原位,方便继续使用独立的无交互 probe,不会突然跳回 Local。temporary 位置旁的终端按钮运行普通交互式 SSH(不附加远端命令),因此不要求目标机器安装 jsh。

超长 DSW endpoint 在位置下拉项中从中间省略,保留 root@dsw…aliyuncs.com 这类可辨识前后缀;悬停可查看经过安全显示处理的完整目标。

deploy 决定目标机器上没有 jsh 时怎么办:"off"(默认)直接运行 remote_shell,取到什么算什么;"persist" 和 "incognito" 会把一份 jsh 送过去,前者在对方 $HOME 留下 dot-files 和二进制缓存(重连免传输),后者用退出即删的沙箱 HOME。Block、cwd 跟踪和退出码都来自 jsh,所以对端只有 sh 时不开 deploy 会静默丢掉这些。

docker = true 时 host 是正在运行的容器名,走 docker exec 而不是 ssh,user 变成容器内的用户(-u);ssh_args、multiplex、login_shell 对容器无意义,会被忽略。容器默认以 root 运行,而旧版 jsh 在 root 下会把 /usr/bin/git 和 /usr/bin/bash 判为不可信 helper,于是 git 补全、git 提示符和 .bashrc 导入在容器里静默消失。容器标签页请搭配修复过这一点的 jsh(jsh CHANGELOG 中的 “a root shell trusts the system helpers it could write”)。

[[remote_hosts]]
name = "build容器"
host = "my-service"
docker = true
user = "devuser"
deploy = "persist"

通常不需要配置从哪拿 jsh:本机装的 jsh 是静态构建时(Linux 安装的默认),launcher 会直接把它出借给目标——不查 release、不联网,远端跑的就是本机这份的同版本。release 只是动态链接或跨架构时的回退。

deploy_artifact 因此只剩一个用途:明确要推另一份构建(比如某个分支的产物)而不是 本机正在用的这份。路径必须是绝对路径,且必须是目标机跑得起来的二进制;--check-config 会在文件不存在、或写了它却没开 deploy 时给出警告。

11. AI 与 Agent 安全边界

AI 总开关、provider 和 endpoint 由配置控制。支持 Anthropic、OpenAI-compatible 和 Ollama wire protocol。ai_base_url 必须是绝对 HTTPS URL,或是明确的 loopback HTTP endpoint(localhost、IPv4 loopback 或 [::1],可带数字端口);该本机例外对三个 provider 一致,便于连接本机兼容服务和代理,任何远程明文 HTTP endpoint 仍会在联网前被拒绝。明确无需鉴权的 loopback 服务可不配置 Key。密钥内容不会写入 TOML;环境变量优先。也可直接在 Settings → AI & Agent → API Key 输入密钥并按 Apply:forge 会将它原子写入 owner-only 的 ~/.config/forge/ai.key,并只把文件路径写入配置。设置面板不会回显已经保存的密钥,再次输入并 Apply 可替换它。

测试本机 provider mock 时可直接使用 loopback HTTP;若选择 HTTPS,仍须让系统 curl 信任包含实际 localhost/loopback SAN 的测试证书,Forge 不会使用 -k 或跳过证书校验。--check-config 会在联网前拒绝所有非 loopback HTTP URL。

也可通过环境变量配置:

export ANTHROPIC_API_KEY='...'
# 或 OPENAI_API_KEY / OLLAMA_API_KEY / 通用 FORGE_AI_API_KEY
forge

若要手工管理密钥文件,可执行:

mkdir -p ~/.config/forge
install -m 600 /dev/null ~/.config/forge/ai.key
read -rsp 'AI API Key: ' FORGE_KEY; printf '\n'
printf '%s\n' "$FORGE_KEY" > ~/.config/forge/ai.key
unset FORGE_KEY
chmod 600 ~/.config/forge/ai.key

并在 config.toml 中设置:

ai_api_key_file = "~/.config/forge/ai.key"

文件必须是当前用户所有的普通文件,Unix 权限不得向 group/other 开放,最大 16 KiB,且只能包含一行非空密钥。环境 Key 优先于文件;FORGE_AI_API_KEY_FILE 可覆盖文件路径。相关配置为 ai_enabled、ai_provider、ai_base_url、ai_api_key_file、ai_model、ai_max_tokens、ai_stream 和 ai_redact_secrets。请求通过系统 curl/Flatpak host bridge 发送;运行 --doctor 可离线检查凭据文件和 curl。右侧聊天面板使用 Ctrl+Alt+Shift+A,Block 选择后 Ctrl+Shift+Q 可发送命令、退出码、cwd 和截断输出。

面板可拖动分隔条,实际宽度会在 400 ms 防抖后写回 ai_panel_width,并在启动、配置热重载和重新打开面板时恢复。输入框中 Enter 与 Ctrl+Enter 均发送,Shift+Enter 换行;输入法正在选词时,Enter 只确认候选,不会误发。焦点位于输入框时,Ctrl+Shift+C/V 也会作用于输入框,而不是后台终端。空会话提供三个快捷提示,它们只填入 composer,绝不会自动发送。

聊天回复默认流式显示(ai_stream = true / FORGE_AI_STREAM):回答在生成过程中逐段出现在会话里,完成时以 provider 返回的完整文本原样落库,与关闭流式时保存的会话完全一致;中途出错时已显示的部分内容保持可见,错误按既有方式提示并可 Retry。流式只用于聊天面板;Agent、命令生成与纠错等严格 JSON 表面始终等待完整回复。关闭 ai_stream 则恢复等待完整回复的旧行为。

发送后状态行提供 Stop;它会终止并回收对应 curl(流式时同样中断传输),而不只是隐藏迟到回复。失败或停止后可 Retry 原请求,generation 仍绑定原 chat,期间新输入的 draft 不会被覆盖。删除 busy chat 和关闭窗口同样会先取消 transport。选中 Block 的 command/exit 会显示为 composer 上方的 context chip,可在空闲时 Clear;Ask Block 失败后,Retry 实际将使用的 pending context 也会明确显示,若输出因行数或字节预算被裁剪,chip 会标出 output truncated。关窗前仍留在内存中的 Ask Block retry 会转成该 chat 的可恢复 draft/context。

New chat 会创建并立即选中一个新会话,旧会话不会被清除。打开 Chats 会话库可搜索和选择所有保留的 chat;首条问题会生成自动标题,也可 Rename。Archive 将 chat 移入归档列表而不删除内容,Unarchive 可恢复;Delete 会先要求确认,再永久移除该 chat。切换 chat 时,未发送 draft、该 chat 实际发给 provider 的选中 Block context 以及当前选中的 chat 都会跟随窗口快照持久化。

每个窗口最多保存 50 条 chat metadata,每个 chat 最多恢复 100 个完整 turn;active 与 archived chat 都计入集合上限。所有 chat 共用一个 8 MiB 紧凑 JSON 总预算,而不是每个 chat 各有 8 MiB。超过全局预算时会优先裁剪最旧内容、保留 chat 条目,并在受影响会话显示 truncated,提示更早内容已不在快照中。工作区的 20 MiB Pane/Tab 上限之外另有 64 KiB 专用于完整 chat metadata;空间紧张时会继续裁剪 payload,而不会静默省略整个 Chats 库。旧版单会话 schema v1 会在读取时自动迁移为 v2 Chats 集合。

运行时和持久化预算彼此独立:Chat 单条输入不超过 64 KiB;live message history 每个 chat 至多 100 个 turn、所有 chat 合计至多 8 MiB;一次 provider 请求保留最近至多 40 个 turn、合计至多 256 KiB;selected Block command/output/cwd 分别限制为 16 KiB/64 KiB/4 KiB;解析后的模型文本不超过 256 KiB,curl stdout/stderr 分别限制为 8 MiB/64 KiB。Chat 与 Agent 的可见 activity buffer 各不超过 1 MiB,Agent 核心 transcript 另有 128 KiB/128 entries 上限。全局最多 4 个 provider 请求并行,其余请求等待槽位且仍可取消。达到 ai_max_tokens 时回答会显示明确的截断提示。更早 history 被请求预算省略时,模型会收到说明;超出 live/persistence 预算时只移除完整旧 pair,在途问题不会被裁掉,并标记 truncated。

selected Block、pane cwd 与配置 shell 不再拼进高信任 system prompt。它们会经过字节截断、JSON 转义和可选脱敏后,作为明确标记的“不可信 terminal/environment data”放入 user-role 请求;命令输出、路径中的提示词、代码围栏或伪造策略都只应作为待分析证据。

后台请求绑定其发起时的稳定 chat ID:切换到其他 chat 不会改变回复目的地,也可让不同 chat 的请求各自完成;如果原 chat 已 Delete,迟到回复会直接丢弃,不能重新创建或污染当前 chat。在途用户 turn、错误回合和命令生成审阅事件不会伪装成已完成回答恢复;待完成或失败的问题会回到可重试 draft,发送期间键入的下一条 draft 也会保留,Ask selected Block 不会清掉已有草稿,关窗会先刷新防抖中的最新内容。开启 ai_redact_secrets 时,持久化脱敏覆盖 active、non-active、archived chat,包括标题、turn、draft 和 Block context,而不只处理当前可见对话。该数据与标签/Pane 状态一起使用有界、原子替换的 owner-only 文件;--safe-mode 不读取也不发布会话库,--no-restore 和显式新工作区仍不领取旧快照,其中 --no-restore 继续按既有语义建立新的可持久化工作区。对话仍可能包含敏感命令或输出,发送和保留前应自行检查。

自然语言转命令与 Agent 坚持 review-first:模型只能提出候选,不会自行写入 PTY、提交 Enter 或执行。在命令面板输入 ? 请求 会把一次性建议固定到当前 Block pane,以块内卡片显示请求、provider、cwd、selected Block context、busy/error 状态和可编辑候选;请求可 Stop/Retry,成功后可 Regenerate、复制或 Insert for review。插入只写入普通 shell 编辑行,不发送 Enter;VTE pane 不提供这张上下文感知卡。

一次性建议、失败命令纠正与 Shell Agent proposal 共用同一套审阅卡逻辑:编辑时实时重算危险模式,Copy 永不写入 PTY,Enter 只触发卡片上明确标出的主操作。已验证的本地纠正只有在文本完全未改且非危险时才显示 Run verified command;任何编辑或新风险都会立即降级成 Insert for review。

Ctrl+Alt+G 或顶部栏的 Agent 开关在当前 active Block pane 打开原生 Shell Agent;开关保持选中时表示 Agent 会话正在激活。Agent 卡显示固定目标 cwd、安全状态、回合进度、实时 prompt readiness 和 proposal 审阅区,活动消息以普通块留在同一条 conversation flow 中;设置按钮显示 provider/model、shell、命令纠正开关和只读自动放行开关。readiness 会区分空闲、已有输入、命令运行中、全屏程序、prompt 初始化和缺少 shell integration,审批失败时给出对应恢复步骤。打开 Agent 时若已有 selected finished Block,它会作为可见的“不可信上下文”chip 附加,也可移除;会话空闲(Ready)时可用 Attach selected Block 把当前选中的 finished Block 附加或替换为新的上下文。请求还会附带有界的 git 元数据(branch、dirty、ahead/behind),与 cwd/shell/OS 一样只作为不可信 user-role 数据发送。Agent 在打开时固定目标 pane,切换标签不会悄悄改变执行目标。VTE pane 不提供 Agent。

Approve & Run 的当前执行边界是本机 native Block pane、直接启动的交互式 bash/zsh,以及本版本自带且已在当前 prompt 完成私有握手的 shell integration。Forge 通过一次性私有 FD 把关联 token 交给启动 shell,脚本读取后立即关闭并清除 FD 变量;token 不进入命令 argv、普通环境快照或 jsh execution journal。managed remote pane、Flatpak host bridge、jsh、fish、PowerShell、未知 shell 和 -c/一次性 wrapper 不提供 Agent 自动提交;这些环境仍可使用 Insert only、普通 AI Chat 和只插入不回车的纠正建议。

审核执行分两阶段:先只插入文本,等 VTE 证明当前编辑器从 prompt anchor 到光标逐字等于审核文本、光标右侧严格为空,再单独发送 Enter;CommandStart 还必须带当前 prompt 私有握手对应的 C/D ID,且上报/渲染的命令身份逐字匹配。leading/trailing whitespace、右提示符、可见 autosuggestion、未闭合引号/heredoc 等无法在时限内形成可信 CommandStart 的情况会 fail closed;若 Enter 已发送但身份随后无法证明,UI 会要求先检查终端再重试,而不会声称“肯定没执行”。需要保留这些 shell UI 特性时使用 Insert only。

这个边界把普通前台子进程伪造的 OSC 生命周期与 Agent observation 隔开,但不把交互 shell 本身当成敌对沙箱:用户加载的 shell rc、函数、hooks 和键位绑定仍属于可信 shell 配置,同一 shell 内代码可读取 shell 私有状态。私有 token 是关联与误绑定防护,不是针对恶意 shell 配置的密码学认证。

一次 Agent 会话的安全流程是:

  1. 输入任务后,模型回复必须是严格 JSON say、run 或 done;夹杂 prose、未知字段、错误类型、过期 proposal 或非法控制字符都会 fail closed,不能退化为可运行命令。用户任务也有 16 KiB 上限。
  2. run 只能包含一条可见单行命令,CR、LF、Tab、NUL、ESC 等控制字符无论来自模型还是编辑结果都会被拒绝。proposal 卡可复制和编辑;风险提示会随编辑实时重算。
  3. 每张卡片可 Reject、Insert only 或显式 Approve & Run。Reject 会进入 transcript 并要求模型换方案;Insert only 把最后编辑值写入普通 shell 编辑行供手动处理,不发送 Enter,并把“未执行”写入 Agent transcript;批准执行的是用户最后编辑后的精确文本。识别到顶层 rm -rf、mkfs、提权、强制 Git 改写、下载后 pipe 到 shell 等模式时,除醒目提示外还必须在显示精确命令的第二个确认框中再次批准。
  4. 批准前再次检查固定 Block prompt:正在运行任务、已有未提交输入、可见右提示/建议或当前 shell 未完成受支持的私有握手时拒绝写入,待 prompt 空闲且严格清空后才能重试。
  5. 已批准命令形成 finished block 后,匹配的 exit code 和有界输出作为 observation 回灌,Agent 才能提出下一步。不相关命令不会被当成该 proposal 的结果。
  6. 模型请求进行中可 Stop 当前 turn,并在保留 Agent session 的前提下 Retry,不会复制 user turn。模型以 done 完成任务后,Follow up 会保留 transcript 并重新开放输入;agent_max_turns 达到上限后,New task 可在同一 pane 清空旧模型上下文并恢复完整回合预算。Cancel Agent 或关闭窗口则取消整个会话并等待 transport 回收。已经由用户批准并启动的普通终端命令不会被这些按钮暗中 kill,仍使用标准 pane/tab 关闭确认管理。若窗口在已批准命令的 finished-block observation 回灌前关闭,重启不会猜测结果或把旧执行绑定到新 PTY;该有效但无法续接的 checkpoint 会被安全废弃,Agent 从新的 Ready 会话开始。

dashboard 和 Settings 中的 AI command correction 开关控制 command_correction_enabled。开启后,Block 命令出现 typo、unknown executable/package、invalid subcommand/option 等窄范围错误时才会提供可编辑纠正;候选不会自动插入或执行。关闭开关会立即阻止新的纠正,也会丢弃仍在解析中的待显示结果。默认开启,可用 FORGE_COMMAND_CORRECTION_ENABLED 临时覆盖;确定性目标提示与本地索引优先,AI 仅为 fallback,完整边界见 docs/SMART_COMMAND_CORRECTION.md。

agent_enabled = false 可独立关闭 Agent,agent_max_turns 限制模型回合数;ai_enabled = false 和 safe mode 都会同时阻止打开。Agent 必须被视为有用户权限的命令执行辅助工具,危险模式提示不是完整 shell 安全分析,也不替代逐字审阅。

agent_auto_approve_readonly 与 FORGE_AGENT_AUTO_APPROVE_READONLY 仅作为旧配置兼容键保留,运行时始终归一化为关闭。所有 proposal 都必须逐条批准。原因是命令文本本身无法证明实际执行对象:alias、function、Git helper、工具的写入/执行 flag,以及读取后会发送给模型的敏感文件都跨越了字符串白名单的安全边界。Settings 会明确显示该能力已停用,旧配置为 true 时 --check-config 会给出迁移警告。

ai_redact_secrets = true 默认遮蔽常见密钥格式,并在持久化前重新处理所有 active、non-active、archived chat 及其 draft/context;但脱敏不是秘密保护边界,发送前仍应检查上下文。--safe-mode 同时关闭 AI 与 Agent。

开发、回归与发布检查见 AI / Agent / Chat 验收矩阵;该矩阵是测试要求,不代表其中所有目标均已实现。

12. 配置保存与快捷键

显式图标/备用字体会以正确的 Pango 列表格式附加,不会因字体名前多出的空格而被忽略;字号、粗体、斜体和保存的设置不变。

默认字体为 JetBrainsMono Nerd Font Mono 14。若系统未安装此字体,显示时会使用系统的 Monospace 等宽字体,避免默认替代字体使字符间距失真;不会改写保存的配置。自定义字体 和字体列表保持原样,已安装的默认字体仍优先使用。安装字体后请重启 Forge。

完整字段见 config.toml.example。保存后自动热重载,Ctrl+Shift+R 手动重载。语法或语义错误不会替换当前有效配置。

应用内设置保存还会:获取进程级 advisory lock、检查加载时 revision、拒绝并发编辑冲突、用 owner-only 临时文件 fsync 后原子替换,并轮换 .bak / .bak.1 两份经过验证的备份。恢复前的当前文件另存为 .before-restore。冲突、验证拒绝、锁超时和 I/O 错误会在窗口中明确提示;内存中的临时改动仍有效,但磁盘不会被覆盖。发生冲突时先重载配置再重新应用改动;必要时运行 forge --restore-config-backup。safe mode 中的设置只影响当前窗口,也会明确提示不会保存。

覆盖或解除快捷键:

[keybindings]
show_remote_picker = "F8"
toggle_ai_panel = false

修饰键名称不区分大小写:Ctrl / Control、Alt / Option 等价,Super / Cmd / Command / Win / Meta 映射为同一跨平台修饰键。数字小键盘的 0–9 与主键区数字共用组合(例如 Ctrl+1);小键盘 Enter 和运算符仍保持独立。若两个 action 使用同一组合,配置检查器会报告冲突。Ctrl+R / Ctrl+P 留给 shell/readline。

[keybindings] 只管理命令面板中可发现的应用动作。Block 视图的上下文键 Alt+Shift+F(过滤)、Ctrl+Shift+B(书签)和 Ctrl+, / Ctrl+.(前后书签) 目前是固定绑定,不能通过该表覆盖或解除。

13. 状态与历史位置

  • 配置:~/.config/forge/config.toml 及 .bak / .bak.1。
  • 窗口快照:~/.config/forge/windows/window-*.active|state。
  • JSONL 命令历史:${XDG_STATE_HOME:-~/.local/state}/forge/history.jsonl,可用配置覆盖。
  • 可选 Block 全量历史:由 block_history_path 指定,可能包含输出。
  • 用户 workflow:~/.config/forge/workflows/*.{toml,yaml,yml}。
  • 已安装示例与 Notebook:${prefix}/share/forge/;默认安装的 ~/.local/share/forge/ 在自定义 XDG_DATA_HOME 下仍是兼容搜索层。

配置、快照与历史包含敏感工作信息,备份或分享前应主动检查。

14. 故障排查

forge --doctor
forge --check-config
FORGE_LOG=debug forge --no-restore
forge --safe-mode
forge-support-bundle .
  • GUI 无法启动:确认 DISPLAY 或 WAYLAND_DISPLAY 以及 GTK/VTE 动态库。
  • 中文输入无预编辑:检查 GTK_IM_MODULE、XMODIFIERS 和 fcitx5/ibus GTK4 模块。
  • Block 缺少准确 exit/cwd:加载对应 shell integration。
  • AI 不可用:检查 ai_enabled、provider 对应密钥、base URL 和 curl。
  • 欢迎 Notebook 找不到:重新安装资产,或设置 FORGE_ASSET_DIR=/path/to/share/forge。
  • workflow 示例找不到:检查 ${prefix}/share/forge/workflows;非默认 prefix 可设置 FORGE_WORKFLOW_DIR。
  • 某个 workflow 文件不出现在面板里:用 FORGE_LOG=warn forge 查看 workflows: skipping <路径>: <原因>,常见原因是字段类型不符(例如 default = 3000 少了引号)、参数名为空或带首尾空格、文件是符号链接。
  • 长命令无通知:检查 notify_long_blocks、阈值、notify-send 和通知服务;通知只在窗口未激活或该 pane 不在当前标签页时弹出。
  • SSH 无目标:添加 [[remote_hosts]] 后按 Ctrl+Shift+S。
  • 配置修改没生效:先运行 --check-config;并发冲突需要重载后再保存。

Block 卡片动作与键盘焦点

每张完成卡片都有始终可见的 Block actions(⋮),可用鼠标、触摸或 Tab + Enter 打开。 它和右键共用操作菜单及提示符安全检查;历史恢复和撤销恢复也不会失去动作。菜单过长时可滚动, Escape 关闭,重复激活不会创建叠加菜单。

悬停/选中的快捷区保留 Copy output 和 Insert for review;插入不会提交执行, 提示符忙碌或已有输入时仍会拒绝。其余复制、过滤、折叠、展开和长输出导航在菜单内。 快捷按钮有键盘焦点时移开鼠标不会隐藏或禁用它;离开快捷区后才恢复正常显示规则。 窄分屏中的 cwd 与 git 名称会省略,tooltip 保留完整可见文本。

Block review:审阅保留的命令记录

选中卡片后,在活动选择边缘点击 Review selection (数量),也可点击完成卡片的 cwd/时长元数据区域,或在常驻 Block actions 菜单中选择 Review Block / Selection。Details 页显示完整保留命令、工作目录、退出状态、 可信时长、命令精确性和完成来源。缺少退出状态不会显示成功;缺少可靠计时不会伪造时长。 输出被截断、从日志恢复、命令只获得尽力捕获等情况会明确说明。

已选多块时,顶部选择器按从旧到新顺序切换记录;Command order 页显示同一顺序的命令 及每条命令的捕获来源。Copy commands 按该顺序复制命令,忽略无命令的后台输出块。 窗口本身不会回填或执行命令,原有提示符和运行中程序保持不变。

审阅是打开时的只读快照;后续完成的块不会插进当前列表。复制会重新检查所审阅的 ID 和命令;任何块已被淘汰或变化时整次拒绝。为保护长会话,最多审阅 64 块和 256 KiB 命令文本;范围过大或缺少记录时会提示缩小选择,禁用复制。输出和图片留在原卡片,不为 审阅创建另一份副本。隐藏控制/双向格式字符会安全显示,并禁用与显示内容不一致的复制。

Escape 或 Close 关闭窗口并把键盘焦点交回打开审阅的历史操作或卡片;仅当该卡片已卸载时 回到 live 终端。关闭不会清除选择或未读计数。窗口不改变 PTY 网格、不展开虚拟化历史, 也不跳到最新输出。Unified 和 VTE 后端保持各自的原有交互。

跨终端区域拖选

在一个命令或输出 VTE 内拖动仍使用原生按字选区。拖动跨过区域边界后,轮廓标记整区选择;复制包含这些区域的全部保留文本(含其 VTE 滚屏),按界面从旧到新排列,而不是只取端点部分行。区域折叠、卸载或内容改变时会撤销选区;复制超过 32 MiB、读取过慢或任一记录失效时整次拒绝,保留原剪贴板。拖选本身不覆盖 PRIMARY 或普通剪贴板;只有明确复制才更新普通剪贴板。

流式 live 终端仍在拖选时暂停显示刷新;复制、继续输入、取消或达到既有缓冲上限后恢复。真正的单区域原生选区可以接替整区选区。GTK/X11 回归通过实际指针事件检查两个拖动方向、顺序、剪贴板边界与暂停数据恢复;可在隔离 Xvfb 中设置 FORGE_XTEST_DRIVER="$PWD/scripts/qa-cross-selection-pointer.py" 运行 scripts/test-gtk-display.sh(需 Python 3、libX11、libXtst)。

Chat 终端模式

用 forge --mode chat --no-restore 或 terminal_mode = "chat" 开启。 设置中的 Terminal Backend → Chat 仅应用到新建和恢复的本地 pane。 右侧显示命令胶囊,左侧保留宽日志输出卡,底部固定原生多行 shell 输入区。 它不依赖 LLM,也不是 AI Chat:补全、历史、多行、密码与交互进程仍走原来的 VTE/PTY。 发送箭头等于一次 Enter,不重新粘贴命令;运行时同一个终端进入结果区,底部有耗时和 Stop。 vim/top 接管原生终端,退出后按实际 shell 状态返回;缺少集成时同一 PTY 继续透传。 复制、搜索、折叠和历史恢复继续使用原始记录。 详见 Chat 验收清单。

分组字号

Ctrl+滚轮根据鼠标所在区域缩放,而不是键盘焦点:顶部栏、左右侧栏(标签、文件树、AI Chats/Tasks)和底部状态栏共用 UI 组;中心终端区域的 Block/Chat/VTE、全部分屏及中心搜索栏使用主内容组。普通滚轮保持原来的滚动行为;独立对话框、全窗浮层及区域之间的分隔条不绑定分组缩放控制器;主内容内部的终端分屏分隔条仍归主内容组。

两组基础字号及倍率独立保存,倍率范围为 0.1–10.0,连续触控板滚动保留小数增量。旧配置加载时从 font 和 font_scale 固定 UI 组的初值;之后只改其中一组不会改变另一组,重启后亦然。UI 组使用 chrome_font_size(如 "14" 点或 "17px")和 chrome_font_scale,主内容使用原来的 font 与 font_scale。

设置中的 Main Content Font Size/Scale 只改主内容;Sidebar & Top Bar Font Size/Scale 只改 UI 组。Ctrl+= / Ctrl+- / Ctrl+0 仍控制主内容组。更改主内容的基础字号不会再连带改变侧顶栏字号。