[pull] main from xintaofei:main - #174
Merged
Merged
Conversation
Plan documents rendered in the message stream expanded to their full height, burying the rest of the turn. Cap the body and reveal a show more/show less footer once it is actually clipped, matching the affordance user messages already use.
The detail drawer printed the agent's result as preformatted text, so the bullets, backticks and bold it writes came through as source. It now renders through the same pipeline as the chat, carrying its own typography: Streamdown sizes headings for the full-width message column, which dwarfs a 12px drawer panel, and its block rhythm never lands at all because Tailwind does not scan node_modules. A long result is capped and revealed behind show more, matching the brief above it. The fade over a clipped block now starts from the panel's own fill rather than the drawer's, so the block dissolves into its surface instead of ending on a stripe.
Claude Code writes the name you set with `/rename` (or `claude -n`, or Ctrl+R in the picker) as a `custom-title` record, separate from the `ai-title` it generates on its own. codeg only ever read `ai-title`, so a session you had already named by hand came back under a machine-written summary, or under its first prompt. Both title paths now read `custom-title` first, and the newest one wins if you renamed more than once. CodeBuddy stores the same record (plus a `topic`); its parser now follows CodeBuddy's own order, and takes the newest generated title instead of the first, which used to pin a long session to the title of its opening exchange. A session you keep working on in the agent's own CLI after importing it also kept the timestamp it had at import: sorted by "recently updated" it sat where it landed months ago, showing a stale time. Scanning for local sessions now refreshes the ones already imported from the same parse it just did — the transcript's own last-activity time into `updated_at`, plus a fresh message count — and broadcasts each one so open sidebars re-sort live. Strictly forward, never backwards, and it leaves the rest to you: your rename, pin, status and the original creation time all survive.
The Task Board and the Automations page overlay the whole workspace, and leaving them meant opening a conversation -- picking one in the sidebar, or starting a new one. Neither page carried an exit of its own, so with the sidebar collapsed the way back was invisible. The window's top-right chrome now carries a back arrow while either route is open. It takes the slot the terminal and aux toggles vacate there -- those hide, since the panels they toggle sit under the overlay -- which puts it immediately left of the settings gear, and the cluster was already sized for three buttons so the geometry is unchanged. The mobile title bar carries the same button in the same position. It returns to the conversation workspace and does nothing else: the active tab is untouched, so whatever was open comes back as it was. Ten locales gain the label.
Opening a folder now always goes through one dialog on every platform: pick the workspace root, then link any number of other directories in as subdirectories of it. Reopened from the folder menu it starts on the link list, so links can be renamed, repaired, or removed later. The native picker becomes a shortcut inside that dialog rather than a separate path that skips the second step. The links are real symlinks — a UI-level merge would be invisible to the agent CLIs, which run with cwd set to the workspace root. Each one is recorded in a new folder_link table, which doubles as the authorization record the workspace path guard consults: the guard still rejects every symlink that escapes the root except the ones the user explicitly created, so a cloned repo shipping `secrets -> ~/.ssh` stays unreadable. The file tree and workspace search descend into authorized links only, which the walkers would otherwise report as leaf files. Name collisions resolve case-insensitively (macOS/Windows filesystems fold case) against the root's real entries — dangling links included, since they occupy a name `exists()` reports as free — other links, and the rest of the batch, disambiguating to `api-2`. Self, ancestor and inside-root picks are rejected rather than silently looping the tree walker. Renames move the entry byte-for-byte so a case-only change is not a no-op, unlink fails loudly rather than stranding a symlink the UI no longer lists, and uploads resolve the link chain once so a swapped link cannot redirect a write. Live watching and git status inside a linked directory are out of scope: the watcher reports paths under the target, which no longer strip against the workspace root.
Starting a task held it at `queued` for the whole launch — creating the worktree, running the folder's init command, spawning the agent CLI — and the board files `queued` under To do. A task three minutes into installing dependencies therefore read as "To do / Queued". The status now splits: `queued` means only that a task waits for a concurrency slot, and the new `preparing` covers everything the launch does before the agent's first turn. Preparing cards sit in the In Progress column with their own chip and offer Cancel like running ones. The session button needs no special case, since it already appears only once a conversation exists, which is exactly when preparing ends. The status column is text, so no migration. Cancelling during setup now stops the init command rather than leaving `pnpm install` to finish in the background. The kill slot opens before the row can read as preparing and stays open for the whole phase, so a cancel arriving during `git worktree add` — seconds on a large repository — is still recorded and the command never starts. A cancel cannot wait for the task lock, which the launch holds across the entire install, so it only raises the request and wakes the launch; the kill happens there, in the task that owns the child, and the pid never outlives it. The whole process tree goes, since the command runs under a shell that would otherwise leave the installer behind. Whether to run the init command is now keyed on a marker in the worktree's private git directory instead of on having just created the worktree. A killed or interrupted install leaves no marker and initializes again on the next launch, where before the tree counted as ready and the agent started on half-installed dependencies. The marker sits outside the working tree, so it never appears in `git status`, and it goes away with the worktree. Scheduling accounts for the new status on the side that needs it: the auto-process budget counts preparing rows in SQL, since it cannot see the engine's in-flight launches, while the pump keeps counting those in memory and would otherwise double-count. Launch slots carry an ownership token so a launch still unwinding cannot release the slot a newer one now holds, and a preparing row no launch owns returns to the queue on the reconcile tick — the pump only picks up queued rows, so it would otherwise sit there until a restart. Ten locales gain the label.
Single-clicking a conversation in the sidebar opens it as a preview tab, and the next single-click takes that slot. The outgoing tab was disconnected unconditionally -- and a preview opened on a conversation that is still working adopts its live connection, since the frontend rekeys an orphaned one onto the new tab and the backend hands back the same connection for the same agent, cwd and session. Replacing the tab therefore killed the agent mid-turn, and the session it belonged to ended with `[Request interrupted by user for tool use]` written into its own transcript. Worktrees had nothing to do with it: two conversations in one folder did the same. The release now applies the policy the other automatic teardowns already had. Viewers detach, idle owners disconnect as before, and an owner still prompting or holding unresolved background work is left running for the idle sweep to reclaim once it settles -- its tab is gone, so nothing else keeps it alive. An explicit disconnect stays unconditional, because its callers carry user intent: an agent switch, a restart to apply settings, a close. The unmount cleanup and the preview release share one predicate so the two cannot drift apart. A connect abandoned or superseded while still in flight used to disconnect whatever connection came back from it. That connection can be one this client already holds under another key, so clicking the second conversation while the first preview was still connecting ended a turn nobody asked to stop. It now tears down only what it spawned itself; a reused connection stays reachable at its own key and is reclaimed by the sweeps.
Every prompt the task engine sends carries wording it writes itself: the worktree guard on a first run, "the previous run was interrupted" on a retry, the review feedback on a return, the whole landing procedure on a merge. That wording is the same for every project and every user, and there was no way to add to it — a house rule about commit messages, a build step that has to pass, a tone you want the agent to keep. Task settings now carry a free-text field per stage. The engine appends it as the last block of that stage's prompt, so it reads as a refinement of the instructions above it rather than part of the task description; `all` is the bucket that goes out with every stage, merge included. Staying at the end also keeps the round marker on the prompt's own opening line, so the transcript still splits into phases as before. The keys are the engine's own stage ids, so a stage added later needs no schema change, and an older settings row simply decodes to no prompts. The dialog was a single column of unrelated rows, and the new field would have made it longer still. It splits into General (the agent and how many tasks run at once), Workflow (the commands and how a task lands) and Prompts. The scope and configuration-source switchers stay above the tabs, since they decide which row is being edited. Within Prompts the stage strip doubles as the field's label and marks the stages that already carry text, so nothing hides behind an unselected segment.
Sending the first prompt in a new-conversation tab could throw the workspace back to a blank "new conversation" page while that prompt kept streaming: the conversation ran on and stayed in the sidebar, but its tab was gone. A draft is device-local until its first prompt creates the conversation row, so for the length of one save debounce the bound tab exists only on this client. Applying a remote snapshot adopted the server's set wholesale, so any snapshot landing in that window erased the tab, and with nothing left the "never leave the workspace blank" branch synthesized a fresh draft. The window is easy to hit: a tab invalidation always bumps the version barrier but only broadcasts when it actually removed a row, so deleting a conversation that has no open tab leaves every client on a stale version with its next save certain to be rejected -- and the rejection hands back exactly the set that predates the send. Snapshots now merge against the tab set the server was last known to hold, recorded from hydration, from every applied snapshot, from an accepted save and from this client's own echoed broadcast. A tab open here but absent from the snapshot is dropped only when the server had it at the last sync, which is what a close on another client looks like; one the server has never seen is a local addition the snapshot predates, and it is kept. The mirror case holds too -- a tab closed here that the snapshot still lists stays closed instead of resurrecting. Either way the merged set is pushed back at the version just learned, since a divergence that is neither echoed nor saved would never converge. Focus resolution follows the same rule: the remote's focused tab no longer pulls the user off a conversation the server has not seen, exactly as it never pulled them off a draft. Rebuilding a tab from a snapshot also carries `workingDir` and `isChat` over from the tab it replaces. The synced payload has no room for either, so a bound chat tab used to lose the scratch directory it is connected in.
Task settings was a flat column of bare rows: every option carried the same weight, and options that are really one decision sat apart from each other -- the merge strategy at the top of Workflow, whether the worktree survives at the bottom, two command fields wedged between them. Every option is now a row inside a card, and the card is the grouping. Merging owns one card, so the strategy and what happens to the worktree afterwards read as the single choice they are; processing automatically shares its card with the concurrency limit that bounds it. The strategy itself is two option cards side by side rather than a dropdown. Both trade-offs -- a tidier history against every step staying traceable -- are readable at once, and a radio dot carries the selection, since the tinted fill alone is nearly invisible in the neutral theme. The checkbox for deleting the worktree became a switch to match the other toggles, so its label drops the "check this by default" phrasing and the nuance moves to the line underneath. The scope and configuration-source switchers keep their place above the tabs but stay out of the card system: they decide which settings row is being edited, not what it contains, so they read as header chrome in muted mini-labels against the cards' titles. The dialog widened to fit the cards, and the tab body has a floor height, so General and Prompts settle at the same size and only Workflow grows it. All five prompt stages shared one placeholder, which taught nothing about what belongs in any of them. Each stage now carries its own example, and each adds something the engine's built-in prompt does not already say: commit habits and scope discipline while the agent works, message language and conflict reporting at the merge, where the built-in already mandates a Conventional Commits message. A note above the stage strip says what the tab is for -- every stage already sends a built-in prompt, and this text is appended to it rather than replacing it. Ten locales gain the new strings.
The path box in the directory browser was a bare input flanked by two loose icon buttons, and the workspace folder dialog parked its "System picker" shortcut in the footer beside Cancel and Next -- a labelled button that reads as a third action of equal weight, sitting far from the field it fills in. Home and the parent-directory jump now live inside the box at its leading edge and the picker at its trailing edge, so the row is one control under one focus ring. Their labels move from native `title` tooltips into the tooltip component, and the parent jump takes an UndoDot rather than a bare chevron. Picking a directory natively now only fills the box in. It used to open the folder outright, so the pick landed in the sidebar with the confirm step skipped entirely, and the link step queued the whole selection the same way. A multi-select lands in the tick list the Add button already reads, exactly as clicking those rows would, and committing stays with the footer. The clone dialog, the new-worktree dialog and both project launchers each carried their own path input, browse button, browser-dialog mount and copy of the rule that decides which picker to open -- the OS dialog only when the workspace is truly local, otherwise the in-app browser that walks the host owning the filesystem. They now share one field that owns all of it, and its icon says which picker is coming.
Silences the clippy unnecessary_sort_by lint that failed CI.
## New - **Multi-folder workspaces.** Link other directories into a workspace as subdirectories when you open a folder — a shared library, a sibling service, the docs repo. The agent reads and edits across all of them, and the file tree and workspace search cover them too. Links can be renamed, recreated or removed from the folder menu, and one switch keeps them out of `git status`. - **Per-stage task prompts.** Append your own instructions to any stage a task runs through — first run, retry, return from review, merge. Each stage carries its own example, and your text is added to codeg's built-in prompt rather than replacing it. - **A Preparing status for tasks.** Worktree setup and dependency install now show as Preparing under In Progress; Queued means only that a task is waiting for a free slot. Cancelling really stops the install, and an interrupted install runs again instead of starting the agent on half-installed dependencies. - **A way back from full-page views.** A back arrow on the Task Board and the Automations page returns you to your conversations, including when the sidebar is collapsed. ## Improved - **Task settings redesigned.** Split into General, Workflow and Prompts, with options grouped in cards. The merge strategy is two choices side by side instead of a dropdown, and what happens to the working copy afterwards now sits with it. - **One path field everywhere.** Home, parent directory and the system picker moved inside the path box, and cloning, new worktrees and new projects all share it. The icon shows which picker opens — the OS dialog for local files, codeg's own browser for files on a server. Choosing a folder fills the field in instead of opening it and skipping the confirm step. - **Task results render as markdown.** Headings, lists and code display properly, and a long result folds behind show more. - **Long plans collapse.** Plan documents cap their height and offer show more / show less, like long messages already do. ## Fixed - **Clicking around the sidebar no longer interrupts a running agent.** Replacing a preview tab used to kill the agent mid-turn and leave "Request interrupted by user" in its transcript. - **A new conversation keeps its tab after the first prompt.** Tab state from your other devices now merges with what is open here instead of replacing it wholesale. - **Imported sessions keep their `/rename` title and a truthful timestamp.** Claude Code and CodeBuddy both. Re-scanning also refreshes already-imported sessions, so ones you keep using in the agent's own CLI sort by real activity. Renames, pins and status are untouched. ----------------------------- # 发布版本 0.23.1 ## 新增 - **工作区支持多文件夹。** 打开文件夹时可将其他目录以子目录形式链接进来——共用的库、隔壁的服务、旁边的文档仓库。智能体可跨目录读写,文件树与工作区搜索一并覆盖。链接可在文件夹菜单中重命名、重建或移除,并支持一键排除出 `git status`。 - **任务提示词按阶段自定义。** 首次执行、重试、评审打回、合并等各阶段均可追加自己的说明。每个阶段附有示例,你写的内容追加在内置提示词之后,不会将其替换。 - **任务新增「准备中」状态。** 创建工作树与安装依赖期间显示为「进行中 / 准备中」,「排队中」则仅表示在等待空闲名额。此时取消会真正中止安装,被中断的安装下次重新执行,不会让智能体在半装的依赖上开工。 - **整页视图可返回。** 任务看板与自动化页面右上角新增返回箭头,可直接回到会话,侧边栏收起时同样可用。 ## 改进 - **任务设置重做。** 拆分为「通用 / 工作流 / 提示词」,选项按卡片归组;合并方式由下拉菜单改为并排两个选项,合并后工作副本的处理方式与其同处一张卡片。 - **路径输入全局统一。** 主目录、上一级与系统选择器收入路径框内部,克隆仓库、新建工作树、新建项目共用同一控件。图标会提示将打开哪种选择器:本地文件为系统对话框,服务器上的文件为 codeg 内置浏览器。选定目录后仅填入路径,不再直接打开并跳过确认步骤。 - **任务结果按 markdown 渲染。** 标题、列表与代码正常显示,结果过长时折叠,可展开查看。 - **长计划可折叠。** 计划文档限制高度并提供展开 / 收起,与长消息一致。 ## 修复 - **点击侧边栏不再中断运行中的智能体。** 此前预览标签被替换时会话会被中途杀掉,记录里还留下一句「Request interrupted by user」。 - **新会话发出首条消息后不再丢失标签页。** 来自其他设备的标签状态改为与本机合并,不再整份覆盖。 - **导入的会话保留 `/rename` 名称与真实活动时间。** Claude Code 与 CodeBuddy 同理。重新扫描会刷新已导入的会话,你在智能体自带 CLI 里继续使用的会话按真实活动时间排序;重命名、置顶与状态不受影响。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )