OpenProgram Docs

文件夹 Git 胶囊#

会话用到的每个工作目录,只要位于 Git 仓库里,它在输入框环境条里的文件夹胶囊就多出一个 git 半边。git 半边回答"这个目录在哪个分支、改了什么",菜单里放聊天时需要的几个 Git 操作,不必离开会话:切分支、在 worktree 里工作、审阅修改、开 PR。

哪些目录有胶囊#

  • 主项目目录:会话绑定了真实项目时。默认的主目录项目没有胶囊——它的仓库是 OpenProgram 自己的存储,不是用户的代码。
  • 每个额外工作目录。
  • 不在 Git 仓库里的目录什么都不显示。

同一个仓库里的两个目录(比如项目根目录和它的一个子目录)分支、修改、PR 都相同,只显示一个 git 半边。每个 git 半边按顺序认领自己的仓库根目录——项目在前,工作目录按列表顺序——顺序最小的显示(components/chat/top-bar/git-chip-registry.ts)。同一仓库的不同 worktree 根目录不同,各自保留 git 半边。

胶囊#

每个文件夹一个凸起胶囊(components/chat/top-bar/folder-pill.ts),中间一条贯通上下的细线分成两段,各自响应 hover 和点击。细线不占宽度,两段的 hover 底色在同一条边界相接;任一段 hover 或展开时细线淡出。左段是文件夹:图标、名字;工作目录的 ✕ 只在 hover 或键盘聚焦时出现。点击打开项目菜单。右段是 git:Solar git-branch,分支名的最后一段(claude/foo 显示 foo;HEAD 游离时显示短提交号),再接未提交的 +N −N diff badge——绿半边、红半边,与文件修改卡片一致。未跟踪的新文本文件按新增行计入。改动全是二进制文件(没有行数)时,badge 显示中性灰色的“N 个文件”,第 3 级的圆点也是灰色,不显示“+0 −0”。干净的目录只显示分支。两段都撑满胶囊高度,hover 底色覆盖整个半边。tooltip 里有仓库、完整分支名和计数。

整行放不下时逐级收缩:

级别 显示
0 全部
1 文件夹名和分支名截到约 12 个字加省略号;Local chip 只留图标
2 收起分支名:分支图标 + diff badge
3 隐藏全部名字;diff badge 变成左绿右红的小圆点

测量规则见 composer-responsive-controls.html。

菜单#

  1. 标题:仓库名;当前目录是附属 worktree 时带 worktree 标签。
  2. 修改:"N 个未提交文件 +N −N"。点击以 workspace 范围打开 Review,它本来就按 Git 对比每个工作目录。发送第一条消息前没有会话可审阅,这一行不响应。与上游有领先 / 落后时接着显示一行。
  3. 分支:筛选框 + 本地分支,按最近提交排序(最多五十个)。点分支去哪里由目录状态决定,没有开关可选:目录干净就地执行 git switch;目录有未提交修改时,分支在仓库旁边的新 worktree 里打开,并把这个文件夹位置换过去,原目录的文件保持不动,标题行右侧写一句"在新 worktree 里打开"。行尾标签只在有信息量时出现:当前所在分支标 当前,已在其他 worktree 检出的分支标 worktree,点它改为去那个目录(git 规定一个分支只能在一处检出)。输入不存在的名字会出现"新建分支"(或"在新 worktree 上新建分支"),回车同效。文件夹位置无法换到 worktree 时始终就地切换。
  4. Worktree:新 worktree 建在仓库旁边的 <repo>-worktrees/<branch>,从不建在仓库里面,原目录的文件和未提交修改保持不动。没有单独的 worktree 列表:有 worktree 的分支就在分支列表里带着标签。"换到 worktree"按目录位置分三种:
    • 工作目录:在会话的目录列表里替换;
    • 未发送草稿的主目录:草稿的项目改指向该 worktree(登记为项目);
    • 已开始会话的主目录:已固定,worktree 作为额外工作目录加入,菜单里有说明。
  5. Pull request:
    • 分支已有打开的 PR:显示"查看 PR #N",在系统浏览器打开;
    • 否则"创建 PR":推送分支(git push -u origin HEAD),以默认分支为基执行 gh pr create --fill,然后打开新 PR。没有 gh、没有 origin、HEAD 游离或当前就在默认分支时禁用,并在下方写明原因。分支相对基分支没有新提交时后端也会拒绝;
    • 有未提交修改时,"让 agent 提交并创建 PR…"把一段现成指令填进输入框(不发送)——写提交信息和 PR 描述是 agent 的活。

git 或 gh 的报错以卡片形式显示在菜单底部,菜单保持打开,方便重试。卡片只有一行人话标题,git 的原始输出放在"查看 git 输出"文字按钮后面,不用原生折叠控件。有一种拒绝会多给内容:就地切换会覆盖未提交修改时,卡片列出文件名,并给两条出路——改为开 worktree 和 带着修改切过去。后者把所有修改(含未跟踪文件)stash 起来,切换后再 pop;pop 冲突时切换保留,修改留在最新的 stash 里,卡片会说明。不提供强制切换,也不提供丢弃修改:agent 会话里不该丢工作。

刷新时机#

不轮询。胶囊在以下时机读取目录状态:挂载和目录变化时;菜单打开时(只有这次会同时列分支、查 PR,二者开销更大);所在会话一轮结束时;窗口重新获得焦点时;项目变化时;同一仓库上任何胶囊执行修改后(op:git-changed)。

后端#

逻辑在 openprogram/worktree/folder_git.py;ws_actions/folder_git.py 把它挪出事件循环并组装回复。每条回复回显 path,并发的多个胶囊各取各的。

动作 回复 做什么
git_folder_status git_folder_status status --porcelain=v2 --branch(分支、上游、领先 / 落后、文件数),diff --numstat HEAD(行数),worktree list,默认分支,是否有 origin,是否有 gh;带 include_branches / include_pr 时再列分支、执行 gh pr view
git_switch_branch git_switch_branch_result git switch [-c] <branch>;带 carry 时 stash push -u → switch → stash pop。拒绝帧带 code(overwrite 附 files,或 stash_conflict)和 detail(git 原始输出)
git_create_worktree git_worktree_created git worktree add [-b] <仓库旁的路径> <branch>
git_create_pr git_pr_created 推送分支,gh pr create --fill,返回 URL(或已存在的打开 PR)

状态读取带 GIT_OPTIONAL_LOCKS=0,不与用户自己的 git 命令争锁;带 GIT_TERMINAL_PROMPT=0,需要凭据的推送直接失败而不是卡住。

实现状态#

  • 项目目录和工作目录的胶囊、同仓库去重、切换 / 新建分支、worktree 新建 / 切换、修改计数与 Review、创建 / 查看 PR、交给 agent:已实现。
  • PR 的基分支选择(目前固定为仓库默认分支)和草稿 PR:未实现。
  • pull / push / fetch 按钮,以及没有上游时相对默认分支的领先 / 落后:未实现。
Last updated · 2026-10-10