Ade Code Remote#581
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
@copilot review but do not make fixes |
|
Warning Review limit reached
More reviews will be available in 24 minutes and 25 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (13)
📝 WalkthroughWalkthroughAdds ChangesADE TUI Remote Mode, Terminal Grid, Context Compaction Lifecycle, and Work Group Expansion
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested labels
✨ Finishing Touches🧪 Generate unit tests (beta)
|
|
@codex review |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/ade-cli/src/tuiClient/app.tsx (3)
10144-10146:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse
gridViewActiveReffor single-terminal controls.A hidden/resumable grid leaves
multiViewRef.currentnon-null, so a visible single terminal pane loses PageUp/Home/End scrollback and visible-output copy. Check whether the grid is shown, not whether it exists.Proposed fix
const terminalForScroll = (activeTerminalSession ?? activeTerminalSessionRef.current); - const terminalPaneVisible = Boolean(terminalForScroll) && !multiViewRef.current; + const terminalPaneVisible = Boolean(terminalForScroll) && !gridViewActiveRef.current;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ade-cli/src/tuiClient/app.tsx` around lines 10144 - 10146, The terminalPaneVisible check incorrectly uses !multiViewRef.current to determine visibility, but a hidden grid view can still leave multiViewRef non-null, disabling scrollback controls for the visible terminal pane. Replace the !multiViewRef.current condition with a check against gridViewActiveRef to accurately determine if the grid is actively shown rather than just checking if it exists.
1156-1160:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPropagate the remote worktree bypass into this guard.
isLaneWorktreeAvailable(lane, { remote: true })is used for drawer availability, but this helper still performs the default local filesystem probe. Inade code remote, callers like new-chat setup, first-send session creation, Claude terminal start/resume, and background launch can incorrectly block on a remoteworktreePaththat does not exist locally.Proposed fix
-function laneWorktreeUnavailableMessage(lane: LaneSummary | null | undefined): string | null { +function laneWorktreeUnavailableMessage( + lane: LaneSummary | null | undefined, + options: { remote?: boolean } = {}, +): string | null { if (!lane) return "No active lane is available."; - if (isLaneWorktreeAvailable(lane)) return null; + if (isLaneWorktreeAvailable(lane, options)) return null; const pathLabel = lane.worktreePath?.trim() || "unknown path"; return `Lane "${lane.name}" is missing its worktree at ${pathLabel}. Restore or recreate the lane before starting a chat.`; }Then pass
{ remote: remoteLaunch }from the remote-aware call sites.As per coding guidelines,
apps/ade-cli/**/*.{ts,tsx}: For ADE CLI changes, verify both headless mode and the desktop socket-backed ADE RPC path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ade-cli/src/tuiClient/app.tsx` around lines 1156 - 1160, The laneWorktreeUnavailableMessage function currently calls isLaneWorktreeAvailable without passing a remote option, which causes it to always perform a local filesystem probe. Modify the function signature to accept an options parameter with a remote property, then pass this options object to the isLaneWorktreeAvailable call. Update all call sites of laneWorktreeUnavailableMessage in remote code paths (such as new-chat setup, first-send session creation, Claude terminal start/resume, and background launch) to pass { remote: true } or { remote: remoteLaunch } depending on whether they are executing in a remote context, so that the worktree availability check respects the remote bypass when appropriate.Source: Coding guidelines
4659-4783:⚠️ Potential issue | 🟠 Major | ⚡ Quick winGate local project-path reads when
remoteLaunchis active.In remote mode,
project.workspaceRootandnextLane.worktreePathare remote paths. This effect can still read and execute a local Claude status-line config, and the slash-command fallback can discover commands from the wrong local checkout. Skip these local fallbacks in remote mode or route them through the remote RPC.Proposed fix
useEffect(() => { + if (remoteLaunch) { + setStatusLineText(null); + setHideVimModeIndicator(false); + return; + } const { config } = readClaudeStatusLineConfig(project.workspaceRoot);- const projectCommands = discoverProjectSlashCommands(nextLane?.worktreePath || project.workspaceRoot); + const projectCommands = remoteLaunch + ? [] + : discoverProjectSlashCommands(nextLane?.worktreePath || project.workspaceRoot);Remember to include
remoteLaunchin the relevant dependency arrays.As per coding guidelines,
apps/{desktop,ade-cli}/**/*.{ts,tsx}: When working in ADE lanes, all file reads, edits, and writes MUST target paths under the lane worktree, never under the main project-root checkout.Also applies to: 6115-6116
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ade-cli/src/tuiClient/app.tsx` around lines 4659 - 4783, The useEffect hook in the status line configuration is reading local config files via readClaudeStatusLineConfig even when remoteLaunch is active, which is incorrect for remote mode where paths are remote. Gate the local config reading and command execution to skip when remoteLaunch is true, or route these operations through remote RPC instead of accessing local files. Additionally, add remoteLaunch to the dependency array of the useEffect hook to ensure proper re-execution when the remote launch state changes.Source: Coding guidelines
🧹 Nitpick comments (1)
apps/ade-cli/src/tuiClient/__tests__/aggregate.test.ts (1)
199-206: ⚡ Quick winConsider adding test coverage for
codex_context_compactionevents.The tests thoroughly cover
context_compactlifecycle scenarios, butaggregate.tsalso handlescodex_context_compactionevents (lines 802-813 in the relevant snippet). The logic differs slightly:codex_context_compactionalways searches for an existing block to merge, whilecontext_compactonly searches whenevent.stateis truthy.📋 Suggested test cases
+ it("collapses a codex_context_compaction begin→end into one block", () => { + const events: AgentChatEventEnvelope[] = [ + env("2026-01-01T12:00:00.000Z", { type: "codex_context_compaction", trigger: "auto", state: "started", turnId: "turn-1" }), + env("2026-01-01T12:00:02.000Z", { type: "codex_context_compaction", trigger: "manual", state: "completed", turnId: "turn-1" }), + ]; + const blocks = aggregate(events).filter((b) => b.kind === "compaction"); + expect(blocks).toHaveLength(1); + expect(blocks[0]).toMatchObject({ kind: "compaction", live: false, trigger: "manual" }); + }); + + it("renders a codex_context_compaction begin as live", () => { + const events: AgentChatEventEnvelope[] = [ + env("2026-01-01T12:00:00.000Z", { type: "codex_context_compaction", trigger: "auto", state: "started", turnId: "turn-1" }), + ]; + const blocks = aggregate(events).filter((b) => b.kind === "compaction"); + expect(blocks).toHaveLength(1); + expect(blocks[0]).toMatchObject({ kind: "compaction", live: true, trigger: "auto" }); + });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ade-cli/src/tuiClient/__tests__/aggregate.test.ts` around lines 199 - 206, The test suite covers context_compact event scenarios comprehensively but lacks coverage for codex_context_compaction events, which have different merging logic in the aggregate function. Add test cases in the test file (similar to the existing context_compact test) to verify that codex_context_compaction events are properly handled by the aggregate function, including scenarios like stateless codex_context_compaction events being treated as completed blocks and verifying that the merging behavior differs from context_compact (since codex_context_compaction always searches for an existing block to merge regardless of state).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/ade-cli/src/tuiClient/app.tsx`:
- Around line 13184-13198: The useEffect hook that handles tiled terminal
resizing reads connectionRef.current but does not include connection in its
dependency array. When the ADE socket reconnects and the connection reference
updates, the effect will not re-run, meaning the new connection won't receive
the tile-sized PTY resize commands. Add connection to the dependency array of
the useEffect hook (currently containing gridViewActive, multiView,
chatWrapWidth, gridRowBudget) so that the terminal resizing logic executes
whenever the connection changes.
In `@apps/ade-cli/src/tuiClient/components/ModelPicker/ModelPickerPane.tsx`:
- Around line 305-310: The useHoveredHitId() hook in the SubProviderTabs
component is being called after conditional early returns, which violates
React's rules of hooks that require hooks to be called unconditionally at the
top level. Move the useHoveredHitId() hook call to the very beginning of the
function, before any conditional statements or early returns (before the
tabs.length check). This ensures the hook is invoked in the same order on every
render, regardless of whether the early return conditions are met.
In `@apps/ade-cli/src/tuiClient/project.ts`:
- Around line 54-75: The trim() method on explicitProjectRoot and
explicitWorkspaceRoot can return empty strings, which are truthy values and
cause the nullish coalescing operator to treat them as valid fallback values
instead of continuing to the next option in the chain. Modify the assignment of
explicitProjectRoot (from args.projectRoot?.trim()) and explicitWorkspaceRoot
(from args.workspaceRoot?.trim()) to coerce empty strings to undefined so that
the ?? operator properly falls through to subsequent fallbacks like
worktree?.projectRoot, gitRoot, and launchCwd when the trimmed values are blank.
In `@apps/desktop/resources/ade-cli-help.txt`:
- Around line 332-337: The remote discovery flags are out of sync between the
help text digest and the README documentation. At
apps/desktop/resources/ade-cli-help.txt lines 332-337, add the missing remote
discovery command examples for `--list-projects` and `--list-sessions` (similar
to the existing `--list-targets` example) to make all three flags discoverable
from the installed help, or alternatively include the nested remote subcommand
help output in the digest. At apps/ade-cli/README.md lines 223-227, either trim
or reword the note that mentions these flags if they are intentionally hidden
from the help digest, or keep the note aligned with the digest by ensuring it
only documents flags that are actually exposed in the help output.
In `@apps/desktop/src/main/services/chat/agentChatService.ts`:
- Around line 13287-13296: The context_compact event with state "started" is
being emitted multiple times for the same compaction part because
message.part.updated can fire repeatedly for the same streaming part. Add
tracking to store which compaction part ids have already had their "started"
event emitted, and only emit the context_compact event with state "started" once
per unique compaction part. Before emitting the event in the compaction type
check, verify that this part id hasn't already triggered a "started" event, and
add the part id to the tracking collection after the first emission to prevent
duplicate live events from appearing.
In `@apps/desktop/src/main/services/lanes/laneService.test.ts`:
- Around line 111-155: The test "includes worktree availability in lane
summaries" creates a temporary directory with fs.mkdtempSync and opens a KV
database with openKvDb but does not clean them up after the test completes. Add
teardown logic to properly close the database by calling db.close() and remove
the temporary directory by calling fs.rmSync(repoRoot, { recursive: true, force:
true }). This cleanup should be executed after all test assertions complete,
either using an afterEach hook specific to this test or by wrapping the test
logic in a try/finally block to ensure cleanup happens regardless of test
success or failure.
---
Outside diff comments:
In `@apps/ade-cli/src/tuiClient/app.tsx`:
- Around line 10144-10146: The terminalPaneVisible check incorrectly uses
!multiViewRef.current to determine visibility, but a hidden grid view can still
leave multiViewRef non-null, disabling scrollback controls for the visible
terminal pane. Replace the !multiViewRef.current condition with a check against
gridViewActiveRef to accurately determine if the grid is actively shown rather
than just checking if it exists.
- Around line 1156-1160: The laneWorktreeUnavailableMessage function currently
calls isLaneWorktreeAvailable without passing a remote option, which causes it
to always perform a local filesystem probe. Modify the function signature to
accept an options parameter with a remote property, then pass this options
object to the isLaneWorktreeAvailable call. Update all call sites of
laneWorktreeUnavailableMessage in remote code paths (such as new-chat setup,
first-send session creation, Claude terminal start/resume, and background
launch) to pass { remote: true } or { remote: remoteLaunch } depending on
whether they are executing in a remote context, so that the worktree
availability check respects the remote bypass when appropriate.
- Around line 4659-4783: The useEffect hook in the status line configuration is
reading local config files via readClaudeStatusLineConfig even when remoteLaunch
is active, which is incorrect for remote mode where paths are remote. Gate the
local config reading and command execution to skip when remoteLaunch is true, or
route these operations through remote RPC instead of accessing local files.
Additionally, add remoteLaunch to the dependency array of the useEffect hook to
ensure proper re-execution when the remote launch state changes.
---
Nitpick comments:
In `@apps/ade-cli/src/tuiClient/__tests__/aggregate.test.ts`:
- Around line 199-206: The test suite covers context_compact event scenarios
comprehensively but lacks coverage for codex_context_compaction events, which
have different merging logic in the aggregate function. Add test cases in the
test file (similar to the existing context_compact test) to verify that
codex_context_compaction events are properly handled by the aggregate function,
including scenarios like stateless codex_context_compaction events being treated
as completed blocks and verifying that the merging behavior differs from
context_compact (since codex_context_compaction always searches for an existing
block to merge regardless of state).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2209060a-2dba-4ef8-9694-3a4f750da31c
⛔ Files ignored due to path filters (3)
docs/features/ade-code/README.mdis excluded by!docs/**docs/features/remote-runtime/README.mdis excluded by!docs/**docs/features/remote-runtime/internal-architecture.mdis excluded by!docs/**
📒 Files selected for processing (52)
apps/ade-cli/README.mdapps/ade-cli/src/cli.tsapps/ade-cli/src/tuiClient/__tests__/ChatView.test.tsxapps/ade-cli/src/tuiClient/__tests__/HeaderFooter.test.tsxapps/ade-cli/src/tuiClient/__tests__/MultiChatGrid.test.tsxapps/ade-cli/src/tuiClient/__tests__/TerminalPane.test.tsxapps/ade-cli/src/tuiClient/__tests__/adeApi.test.tsapps/ade-cli/src/tuiClient/__tests__/aggregate.test.tsapps/ade-cli/src/tuiClient/__tests__/appInput.test.tsapps/ade-cli/src/tuiClient/__tests__/appPolling.test.tsxapps/ade-cli/src/tuiClient/__tests__/cli.test.tsxapps/ade-cli/src/tuiClient/__tests__/connection.test.tsapps/ade-cli/src/tuiClient/__tests__/feedback.test.tsapps/ade-cli/src/tuiClient/__tests__/project.test.tsapps/ade-cli/src/tuiClient/__tests__/remoteLauncher.test.tsapps/ade-cli/src/tuiClient/adeApi.tsapps/ade-cli/src/tuiClient/aggregate.tsapps/ade-cli/src/tuiClient/app.tsxapps/ade-cli/src/tuiClient/cli.tsxapps/ade-cli/src/tuiClient/components/ChatView.tsxapps/ade-cli/src/tuiClient/components/FooterControls.tsxapps/ade-cli/src/tuiClient/components/Header.tsxapps/ade-cli/src/tuiClient/components/ModelPicker/ModelPickerPane.tsxapps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerGeometry.test.tsapps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerGeometry.tsapps/ade-cli/src/tuiClient/components/MultiChatGrid.tsxapps/ade-cli/src/tuiClient/components/TerminalPane.tsxapps/ade-cli/src/tuiClient/connection.tsapps/ade-cli/src/tuiClient/format.tsapps/ade-cli/src/tuiClient/project.tsapps/ade-cli/src/tuiClient/remoteLauncher.tsapps/ade-cli/src/tuiClient/types.tsapps/desktop/resources/ade-cli-help.txtapps/desktop/scripts/regen-ade-cli-help.cjsapps/desktop/src/main/services/chat/agentChatService.test.tsapps/desktop/src/main/services/chat/agentChatService.tsapps/desktop/src/main/services/lanes/laneService.test.tsapps/desktop/src/main/services/lanes/laneService.tsapps/desktop/src/main/services/remoteRuntime/remoteBootstrap.test.tsapps/desktop/src/main/services/remoteRuntime/remoteBootstrap.tsapps/desktop/src/renderer/components/chat/AgentChatMessageList.tsxapps/desktop/src/shared/types/chat.tsapps/desktop/src/shared/types/lanes.tsapps/ios/ADE/Models/RemoteModels.swiftapps/ios/ADE/Views/Work/WorkChatRichCardViews.swiftapps/ios/ADE/Views/Work/WorkContextCompactDivider.swiftapps/ios/ADE/Views/Work/WorkErrorAndMessageHelpers.swiftapps/ios/ADE/Views/Work/WorkEventMapping.swiftapps/ios/ADE/Views/Work/WorkModels.swiftapps/ios/ADE/Views/Work/WorkTimelineHelpers.swiftapps/ios/ADE/Views/Work/WorkTranscriptParser.swiftapps/ios/ADETests/ADETests.swift
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e8aa6cc1a5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (query.startsWith("/") || query.startsWith("~")) { | ||
| return await ensureProject(client, query); |
There was a problem hiding this comment.
Expand remote-home project paths before registering
When a user passes a remote-home path like --project '~/src/app', this branch sends the literal ~ over JSON-RPC to projects.add; the remote registry normalizes paths with Node path.resolve, not a shell, so it looks for <remote cwd>/~/src/app and rejects an otherwise valid project. Quoting ~ is the only way to avoid local-shell expansion to the local home, so expand it on the remote side (or via an RPC helper) before registering the project.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3f8964eea4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (typeof lane?.worktreeAvailable === "boolean") { | ||
| return lane.worktreeAvailable; | ||
| } | ||
| if (options.remote) return true; |
There was a problem hiding this comment.
Honor remote worktrees in start-chat guards
In remote ADE Code sessions connected to a compatible older remote runtime (or any lane payload that omits worktreeAvailable), this new remote bypass only works for callers that pass { remote: true }; the chat-start guards still go through laneWorktreeUnavailableMessage(lane), which calls isLaneWorktreeAvailable(lane) without options and then probes lane.worktreePath on the local machine. That makes /new chat, first-send session creation, and Claude terminal launch reject valid remote lanes as “missing its worktree” whenever the remote path is not present locally, even though the RPC actions would run on the remote host.
Useful? React with 👍 / 👎.
…e fix Fixes the macOS auto-update crash (v1.2.4's ~1.2GB universal update overran Squirrel.Mac's in-memory download path): - Per-arch mac builds replace the universal build: electron-builder --arm64 --x64 with per-arch artifact names; afterPack prunes the non-matching darwin runtime sidecar; validator discovers + validates each arch (host-arch deep smoke); notarize loops per dmg; publish drops blockmaps (clean 5-asset release). Halves the update download (~703MB arm64, verified locally) — well under the size that crashed. - Whisper base.en model (141MB) is no longer bundled; it downloads at runtime on first dictation (streamed to disk, sha256-verified, retried) into userData, with a Settings download UX. New whisperModelStore + tests. - Launch-gate quitCommand now stops the brain via (path-independent, handles the KeepAlive launchd service) + pid-kill fallback, instead of a hardcoded /Applications path that broke for worktree/non-standard installs. Covered by new tests. - Homebrew tap bump regenerates an arch-conditional cask (on_arm/on_intel) from both per-arch DMG digests; workflow now calls the single-source script with deploy-key auth. Also includes v1.2.5 changelog + docs.json registration. iOS Work-tab changes (#581) ship via TestFlight build 1.1.10 (7). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Describe the change.
What Changed
Key files and behaviors.
Validation
How you tested.
Risks
Anything to watch.
Summary by CodeRabbit
Release Notes
New Features
ade code remotecommand for launching on remote desktop machines with interactive project/session discoveryImprovements
ade codeandade skillcommandsBug Fixes
Greptile Summary
This PR adds
ade code remote— a new CLI subcommand that discovers saved remote desktop machines, negotiates a project and optional session interactively, then bridges the local ADE TUI over an SSH-backed TCP tunnel. It also introduces compaction lifecycle visualization, expandable/collapsible work groups, terminal session support in the multi-chat grid, and session-scoped notice routing.remoteLauncher.ts(new, 1152 lines): SSH RPC client, interactive selection, local TCP bridge, andrunAdeCodeRemoteentry point wired intocli.ts.remoteBootstrap.ts: adds bundled agent-skills directory upload with directory-level SHA-256 skip check and atomic staging-then-rename.agentChatService.ts/aggregate.ts: compaction events gainstate: \"started\" | \"completed\"so the UI can show a live spinner; aggregator pairs events across turn boundaries viafindCompactionBlockForCompletion.laneService.ts: skips git operations for unavailable worktrees and exposesworktreeAvailableonLaneSummaryfor remote clients.Confidence Score: 5/5
The PR is safe to merge. Remote mode explicitly skips local side-effects to avoid corrupting local project state.
The ade code remote plumbing is new code with no regressions on existing local paths. Compaction lifecycle changes are additive — legacy events with no state field are handled correctly as live: false. The lane worktree fix is a safe early-return. No data loss or auth boundary issues were found.
remoteLauncher.ts (buildRemoteRuntimeRpcCommand duplicates desktop logic) and aggregate.ts (findCompactionBlockForCompletion fallback scan is turn-agnostic).
Important Files Changed
runAdeCodeRemote.buildRemoteRuntimeRpcCommandduplicates the desktop counterpart and must be kept in sync.ensureAgentSkillsReadyis idempotent so double-calls in the channel-fallback loop are safe.lastCompactionTriggercorrectly threads the real trigger from begin to end event.findCompactionBlockForCompletionfallback handles cross-turn compaction but could prematurely close an unrelated live block if a stale completed event arrives.worktreeAvailableon LaneSummary correctly exposes the server-side check to remote clients.skipRuntimeCompatibilityCheckto bypass build-hash and project-root mismatch checks for remote runtimes.isInProgressflag for live spinner chip; layout refactor correctly positions trailing gradient in both states.Reviews (3): Last reviewed commit: "fix(opencode): dedupe compaction parts w..." | Re-trigger Greptile