Conversation
- Add IPC suggestLaneName for AI-derived lane name prefixes from the prompt - Work new-chat draft: optional parallel mode with per-model configure (model, reasoning, permissions, Codex execution mode) - On send: create child lanes per model, open chats, send prompt, navigate to Lanes with multi-select - Lanes: laneIds + workFocus query for split columns and work-emphasis tiling (layout v6) Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
- Allow images in parallel mode (same refs sent to every child session); cap via PARALLEL_CHAT_MAX_IMAGES - Filter @ picker to images; file input accept=image/*; validate paste/drop - Refined parallel launch card, entry button, send enables with images-only prompt - Steer fallback includes attachment paths; image-only send uses short default line Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
- Replace image-only parallel rules with same file/image support as single chat - Cap parallel attachments via PARALLEL_CHAT_MAX_ATTACHMENTS (12) - Naming seed and empty-message default text cover mixed attachments Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
…structions (#135) * Add integration proposal preferred lane column and resolver prompt types - Store preferred_integration_lane_id on integration_proposals - Extend SimulateIntegrationArgs, CommitIntegrationArgs, CreateIntegrationPrArgs - Add PrAiResolutionStartArgs.additionalInstructions and PrepareResolverSessionArgs field Co-authored-by: Arul Sharma <arul28@users.noreply.github.com> * Integrate into existing lanes, simulate parent-head conflicts, append resolver notes - createIntegrationPr: optional existingIntegrationLaneId merges into that worktree - simulateIntegration: mergeIntoLaneId for merge-tree vs parent head and sequential preview from that HEAD - createIntegrationLaneForProposal: use preferred_integration_lane_id when no binding exists - commitIntegration: dirty-check preferred lane; persist preferred id override - prepareResolverSession: append operator instructions to prompt.md - IPC: pass additionalInstructions from aiResolutionStart Co-authored-by: Arul Sharma <arul28@users.noreply.github.com> * UI: merge-into lane picker, re-simulate flow, optional resolver instructions - CreatePrModal: merge-into select, simulation and save proposal preference - IntegrationTab: apply merge-into with proposal replace, advisories, live PR simulate uses integration lane head - PrAiResolverPanel: optional instructions textarea sent as additionalInstructions Co-authored-by: Arul Sharma <arul28@users.noreply.github.com> * Address PR review: merge-into HEAD persistence, dirty checks, safer proposal swap - Fail simulateIntegration when merge-into lane HEAD cannot be resolved (Codex) - Store merge_into_head_sha on proposals; warn on drift when adopting preferred lane - createIntegrationLaneForProposal: assertDirtyWorktrees for sources + preferred lane; optional allowDirtyWorktree - IntegrationTab: reorder apply-merge flow (update before delete), gate actions on mergeIntoLaneBusy, include liveIntegrationLaneId in simulation reset key, filter source lanes from merge-into picker, lane terminology and advisory copy, dirty-worktree confirm for prepare lane - CreatePrModal: runWithDirtyWorktreeConfirmation around createIntegrationLaneForProposal - Fix SimulateIntegrationArgs JSDoc (pairwise vs sequential merge base) Co-authored-by: Arul Sharma <arul28@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Arul Sharma <arul28@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis PR introduces lane name suggestion from prompts via AI, extends integration proposals to support merge-into lanes with conflict analysis, adds custom instructions to conflict resolution, implements parallel chat mode in the UI with work-focus tiling, and extends the database schema with integration tracking fields. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~55 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/desktop/src/renderer/components/lanes/LanesPage.tsx (1)
1147-1176:⚠️ Potential issue | 🟡 MinorAdding
lanesByIdto dependencies may cause unintended effect re-runs.The
eslint-disablecomment on line 1146 was originally to suppress warnings about omittingprepareCreateDialogto prevent dialog resets on lane refresh. However, addinglanesByIdto the dependency array (line 1176) now causes this effect to re-run whenever any lane data changes.This could lead to:
- Unexpected lane re-selection when lanes refresh in the background
setPinnedLaneIds(new Set())clearing pins on every lane update whenlaneIdsparam is presentConsider extracting the URL parameter handling into a separate effect that only depends on
params, or using a ref to track whether the URL params have already been processed.🛠️ Suggested approach: split the effect or guard against re-processing
+ const processedLaneIdsRef = useRef<string | null>(null); + useEffect(() => { const laneIdsRaw = params.get("laneIds"); const laneId = params.get("laneId"); const sessionId = params.get("sessionId"); const inspectorTabParam = params.get("inspectorTab"); if (params.get("action") === "create") { prepareCreateDialog(); } if (laneIdsRaw) { + // Skip re-processing if we already handled this exact laneIds value + if (processedLaneIdsRef.current === laneIdsRaw) return; const parsed = laneIdsRaw.split(",").map((s) => s.trim()).filter(Boolean); const valid = parsed.filter((id) => lanesById.has(id)); if (valid.length) { + processedLaneIdsRef.current = laneIdsRaw; selectLane(valid[0]!); setActiveLaneIds(valid); setPinnedLaneIds(new Set()); // ... } } // ... }, [params, selectLane, focusSession, setLaneInspectorTab, lanesById]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/components/lanes/LanesPage.tsx` around lines 1147 - 1176, The current useEffect couples URL param processing with lanesById, causing re-runs on lane updates; extract the URL-params logic into a new effect that only depends on params (handling laneIds/laneId/inspectorTab/sessionId and calling selectLane, setActiveLaneIds, setPinnedLaneIds, setLaneInspectorTab, focusSession) and remove lanesById from that effect, and keep prepareCreateDialog either in a separate effect that runs only when params.get("action") === "create" (dependent on params) or use a ref guard to ensure prepareCreateDialog is only invoked once per navigation; ensure any validation that needs lanesById (e.g., filtering valid ids) is performed via a short-lived lookup inside the params-only effect or moved to a second effect that runs when lanesById changes but does not re-run prepareCreateDialog or clear pinned IDs.apps/desktop/src/renderer/components/chat/AgentChatComposer.tsx (1)
1058-1078:⚠️ Potential issue | 🟠 MajorRevalidate the parallel attachment cap before submit.
The new limit is only enforced while adding files. If a user attaches more than
PARALLEL_CHAT_MAX_ATTACHMENTSin single-model mode, switches to parallel mode, and sends, this branch still launches the run.🐛 Suggested fix
if (parallelChatMode) { if (busy || parallelLaunchBusy) return; if (parallelModelSlots.length < 2) return; + if (attachments.length > PARALLEL_CHAT_MAX_ATTACHMENTS) { + setAttachError(`Remove files until only ${PARALLEL_CHAT_MAX_ATTACHMENTS} remain for parallel launch.`); + return; + } const hasPrompt = draft.trim().length > 0; const hasAttachments = attachments.length > 0; if (!hasPrompt && !hasAttachments) return;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/components/chat/AgentChatComposer.tsx` around lines 1058 - 1078, In submitComposerDraft, revalidate the parallel-mode attachment cap before allowing send: inside the parallelChatMode branch (function submitComposerDraft) check attachments.length against PARALLEL_CHAT_MAX_ATTACHMENTS and bail out (same as the existing hasPrompt/hasAttachments checks) if it exceeds the limit so onSubmit() cannot be called when attachments.length > PARALLEL_CHAT_MAX_ATTACHMENTS; keep the other guards (busy, parallelLaunchBusy, parallelModelSlots.length) intact and ensure the check references the attachments array and PARALLEL_CHAT_MAX_ATTACHMENTS constant.
🧹 Nitpick comments (2)
apps/desktop/src/main/services/ipc/registerIpc.ts (1)
4788-4790: BoundadditionalInstructionslength before forwarding to resolver session prep.This field is forwarded into prompt generation. Add a max length guard to prevent oversized prompt artifacts and avoid avoidable token/cost spikes.
✂️ Suggested guard
- const additionalInstructions = typeof arg?.additionalInstructions === "string" && arg.additionalInstructions.trim().length > 0 - ? arg.additionalInstructions.trim() - : null; + const MAX_ADDITIONAL_INSTRUCTIONS_CHARS = 4_000; + const rawAdditionalInstructions = + typeof arg?.additionalInstructions === "string" ? arg.additionalInstructions.trim() : ""; + if (rawAdditionalInstructions.length > MAX_ADDITIONAL_INSTRUCTIONS_CHARS) { + throw new Error(`Additional instructions must be ${MAX_ADDITIONAL_INSTRUCTIONS_CHARS} characters or fewer.`); + } + const additionalInstructions = rawAdditionalInstructions.length > 0 ? rawAdditionalInstructions : null;As per coding guidelines: Electron desktop app — check for IPC security, proper main/renderer process separation, and React best practices.
Also applies to: 4847-4847
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/main/services/ipc/registerIpc.ts` around lines 4788 - 4790, The current assignment for additionalInstructions can accept arbitrarily long strings and is later forwarded into prompt generation; add a max-length guard (e.g., MAX_ADDITIONAL_INSTRUCTIONS = 1000 or a project-consistent limit) and enforce it when setting additionalInstructions in registerIpc.ts: if arg?.additionalInstructions is a string, trim it and then either truncate to the max length or reject/normalize it before assigning to additionalInstructions so oversized input cannot be forwarded to the resolver session prep/prompt generation; update any callers that expect null vs truncated string accordingly (refer to the additionalInstructions variable and the code path that forwards it to the resolver session prep).apps/desktop/src/renderer/components/prs/CreatePrModal.tsx (1)
799-805: Either store the preparation result here or drop the unreachable merge-results branch.
integrationResultis only ever reset tonullin this component, so the Step 3 merge-results panel at Lines 2198-2238 cannot render. IfcreateIntegrationLaneForProposalstill returns merge details, this is the spot to capture them.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/components/prs/CreatePrModal.tsx` around lines 799 - 805, The Step 3 "merge-results" UI never shows because the code calls runWithDirtyWorktreeConfirmation(... run: async (...) => window.ade.prs.createIntegrationLaneForProposal(...)) but never captures or stores the returned merge details into the component state (integrationResult), so integrationResult stays null; either remove the unreachable merge-results branch or store the API response here by awaiting the createIntegrationLaneForProposal call inside run and calling setIntegrationResult(response) (or the appropriate state setter) so the existing merge-results panel can render; reference runWithDirtyWorktreeConfirmation, createIntegrationLaneForProposal, and the integrationResult state setter when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/desktop/src/main/services/chat/agentChatService.ts`:
- Around line 4426-4438: The current guard returns fallback() when
requestedModelId or sourceLaneId are empty, disabling AI suggestions; change the
initial check to only require prompt (i.e., remove requestedModelId/sourceLaneId
from the if that calls fallback()), keep the existing try/catch that attempts
resolveLaneLaunchContext to set cwd (laneWorktreePath) and fall back to
projectRoot on error, and ensure any later code that actually needs a model or
lane uses the existing model-fallback chain rather than this early return; refer
to prompt, requestedModelId, sourceLaneId, fallback(), resolveLaneLaunchContext
and the cwd/laneWorktreePath assignment when making the change.
- Around line 4476-4479: The returned auto-title must be run through the
lane-safe normalizer and validated before returning: after calling
sanitizeAutoTitle(result.text.trim(), 56) run the project’s lane-safe normalizer
(e.g., normalizeLaneName or ensureLaneSafe) on the sanitized value and verify it
produces a non-empty, valid lane string; if the normalized result is
empty/invalid, call fallback() instead; update the return path in the function
containing sanitizeAutoTitle(...) and the existing fallback() usage to perform
this post-normalization and validation.
In `@apps/desktop/src/main/services/ipc/registerIpc.ts`:
- Around line 3800-3803: Add runtime validation at the IPC boundary for
IPC.agentChatSuggestLaneName by parsing the incoming payload before calling the
service: implement or reuse a validator named parseAgentChatSuggestLaneNameArgs
that accepts the raw arg and throws on invalid shape, invoke it inside the
handler to produce a typed value, then pass that validated result to
ctx.agentChatService.suggestLaneNameFromPrompt; update the handler signature to
accept the raw arg and remove direct reliance on static typing (keep references
to IPC.agentChatSuggestLaneName, AgentChatSuggestLaneNameArgs,
parseAgentChatSuggestLaneNameArgs, and suggestLaneNameFromPrompt to locate the
change).
In `@apps/desktop/src/renderer/components/chat/AgentChatPane.tsx`:
- Around line 1721-1738: The effect currently re-seeds lanes whenever
parallelModelSlots.length < 2, which wipes user changes on remove; change it to
only seed when enabling or when the list is empty: in the useEffect that
references parallelChatMode, parallelModelSlots, currentNativeControls, modelId,
reasoningEffort, executionMode, replace the guard "if (parallelModelSlots.length
>= 2) return" with "if (parallelModelSlots.length > 0) return" (or explicitly
"if (parallelModelSlots.length !== 0) return") so it only creates slots when
parallelChatMode becomes true and there are no slots; keep cloning via
cloneParallelSlotFromComposer with currentNativeControls, modelId,
reasoningEffort, executionMode and call setParallelModelSlots as before, and
ensure the dependency list still includes the relevant props; alternatively, if
you need to seed only on the transition from false->true, use a ref to track
previous parallelChatMode and only seed when prev was false and current is true
and parallelModelSlots.length === 0.
- Around line 1919-2030: The catch block must handle partial successes by either
compensating (best-effort cleanup) or routing the user to the lanes/sessions
that were created; update the catch for submitError to inspect createdLaneIds
and sessionByLane and (a) if a lanes delete API exists (use
window.ade.lanes.delete or deleteChild) attempt to delete each created child
lane inside a try/catch (log but suppress errors) and clear sessionByLane, or
(b) if you choose not to delete, navigate the user to the created lanes and open
the created sessions by reusing the existing code that sets work view state and
calls navigate with q.set("laneIds", createdLaneIds.join(",")); ensure you run
this compensation/routing before restoring draft/attachments and only then
setError(message) so retries won’t silently duplicate orphan lanes.
- Around line 1876-1885: The code permits empty modelId values in
parallelModelSlots, so add a validation before creating child lanes: check
parallelModelSlots for any empty or falsy s.modelId (e.g.,
parallelModelSlots.some(s => !s.modelId)) and if found call setError with a
clear message (e.g., "All parallel lanes must have a model selected.") and
return; place this check near the existing duplicate-model and attachments
checks to prevent agentChat.create(...) from being invoked with blank modelIds.
- Around line 828-830: onClaudeModeChange currently only sets
claudePermissionMode via patchParallelSlot(idx, { claudePermissionMode: mode })
but the launch path uses slot.interactionMode to decide how to create/send
Claude sessions; update onClaudeModeChange to patch both claudePermissionMode
and interactionMode (e.g., patchParallelSlot(idx, { claudePermissionMode: mode,
interactionMode: mode })) so selecting a Claude mode keeps the parallel slot's
interactionMode in sync with claudePermissionMode; mirror the same behavior for
onClaudePermissionModeChange if needed so both handlers maintain consistency.
- Around line 2748-2752: The onParallelChatModeChange handler currently calls
setAttachments(...slice(...)) which silently drops files; instead, in the
onParallelChatModeChange function check attachments.length against
PARALLEL_CHAT_MAX_ATTACHMENTS and if enabling would exceed the limit, prevent
calling setParallelChatMode(true) and surface an explicit UI message
(toast/alert/modal) that states how many attachments must be removed and offers
a confirmation to proceed (or a button to open attachments manager); only call
setParallelChatMode(true) and then setAttachments(...) to trim after the user
confirms, otherwise leave attachments unchanged — adjust code paths around
setParallelChatMode, setAttachments, PARALLEL_CHAT_MAX_ATTACHMENTS and add the
user prompt/notification logic.
In `@apps/desktop/src/renderer/components/prs/CreatePrModal.tsx`:
- Around line 1541-1556: Update the user-facing copy to use "lane" terminology
and explicitly state the action on save: replace the option text "New
integration branch" with something like "New integration lane" (in the dropdown
rendering inside CreatePrModal where integrationMergeIntoOptions is mapped) and
rewrite the helper text below the select so it explicitly states what ADE will
do on save — e.g., "When set, simulation includes conflicts against that lane's
current HEAD. On save, ADE will prepare merges into that lane instead of
creating a new lane." Ensure the changes are applied to the JSX around
integrationMergeIntoOptions and integrationSources so the option label and the
explanatory div reflect the new lane-centric, stateful wording.
In `@apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx`:
- Around line 2895-2898: The Create PR button's disabled logic (variable
isDisabled in IntegrationTab.tsx) doesn't account for resimulation activity so a
fast click can commit a proposal that's about to be replaced; update the
isDisabled expression (the same place that checks commitBusy, mergeIntoLaneBusy,
selectedProposal.overallOutcome, hasUnresolved, and
selectedProposalTargetLaneId) to also include resimBusy (or whatever boolean
tracks handleResimulate activity) so the button is disabled while
handleResimulate() is running.
- Around line 3168-3169: The memo's dependency array for the useMemo that
renders IntegrationTab is missing mergeIntoLaneDraft, causing stale UI; add
mergeIntoLaneDraft to that dependency list (the same array that currently
includes prs, selectedPr, selectedPrId, mergeContextByPrId, laneById, ...
nextManualResolutionLaneId) so the memo recalculates when the draft changes.
In `@apps/desktop/src/shared/types/conflicts.ts`:
- Line 411: The renderer call sites in ResolverTerminalModal.tsx are not passing
the newly-added additionalInstructions field through to prepareResolverSession;
update the UI flow so that wherever prepareResolverSession (or the IPC wrapper
that calls it) is invoked from ResolverTerminalModal, you include the
additionalInstructions value from the component/state/props and forward it in
the payload and any typed IPC call. Concretely, locate the two invocation points
in ResolverTerminalModal.tsx that build the resolver request and add
additionalInstructions?: string | null to that object (and to any intermediary
handler/prop signatures) so the value flows into prepareResolverSession with the
correct type. Ensure TypeScript types remain consistent with the shared
conflicts type.
In `@apps/ios/ADE/Resources/DatabaseBootstrap.sql`:
- Around line 548-550: The DB schema added two TEXT columns
(preferred_integration_lane_id and merge_into_head_sha); update the iOS model
and DAO to surface them: add optional String? properties named
preferredIntegrationLaneId and mergeIntoHeadSha to IntegrationProposal
(RemoteModels.swift) and the corresponding fields to IntegrationProposalRow
(Database.swift), update the fetchIntegrationProposals SELECT to include
preferred_integration_lane_id and merge_into_head_sha and map those columns into
the new properties, and ensure any initializer/decoder and database-to-model
mapping code converts snake_case column names to the camelCase property names
and safely handles nulls.
---
Outside diff comments:
In `@apps/desktop/src/renderer/components/chat/AgentChatComposer.tsx`:
- Around line 1058-1078: In submitComposerDraft, revalidate the parallel-mode
attachment cap before allowing send: inside the parallelChatMode branch
(function submitComposerDraft) check attachments.length against
PARALLEL_CHAT_MAX_ATTACHMENTS and bail out (same as the existing
hasPrompt/hasAttachments checks) if it exceeds the limit so onSubmit() cannot be
called when attachments.length > PARALLEL_CHAT_MAX_ATTACHMENTS; keep the other
guards (busy, parallelLaunchBusy, parallelModelSlots.length) intact and ensure
the check references the attachments array and PARALLEL_CHAT_MAX_ATTACHMENTS
constant.
In `@apps/desktop/src/renderer/components/lanes/LanesPage.tsx`:
- Around line 1147-1176: The current useEffect couples URL param processing with
lanesById, causing re-runs on lane updates; extract the URL-params logic into a
new effect that only depends on params (handling
laneIds/laneId/inspectorTab/sessionId and calling selectLane, setActiveLaneIds,
setPinnedLaneIds, setLaneInspectorTab, focusSession) and remove lanesById from
that effect, and keep prepareCreateDialog either in a separate effect that runs
only when params.get("action") === "create" (dependent on params) or use a ref
guard to ensure prepareCreateDialog is only invoked once per navigation; ensure
any validation that needs lanesById (e.g., filtering valid ids) is performed via
a short-lived lookup inside the params-only effect or moved to a second effect
that runs when lanesById changes but does not re-run prepareCreateDialog or
clear pinned IDs.
---
Nitpick comments:
In `@apps/desktop/src/main/services/ipc/registerIpc.ts`:
- Around line 4788-4790: The current assignment for additionalInstructions can
accept arbitrarily long strings and is later forwarded into prompt generation;
add a max-length guard (e.g., MAX_ADDITIONAL_INSTRUCTIONS = 1000 or a
project-consistent limit) and enforce it when setting additionalInstructions in
registerIpc.ts: if arg?.additionalInstructions is a string, trim it and then
either truncate to the max length or reject/normalize it before assigning to
additionalInstructions so oversized input cannot be forwarded to the resolver
session prep/prompt generation; update any callers that expect null vs truncated
string accordingly (refer to the additionalInstructions variable and the code
path that forwards it to the resolver session prep).
In `@apps/desktop/src/renderer/components/prs/CreatePrModal.tsx`:
- Around line 799-805: The Step 3 "merge-results" UI never shows because the
code calls runWithDirtyWorktreeConfirmation(... run: async (...) =>
window.ade.prs.createIntegrationLaneForProposal(...)) but never captures or
stores the returned merge details into the component state (integrationResult),
so integrationResult stays null; either remove the unreachable merge-results
branch or store the API response here by awaiting the
createIntegrationLaneForProposal call inside run and calling
setIntegrationResult(response) (or the appropriate state setter) so the existing
merge-results panel can render; reference runWithDirtyWorktreeConfirmation,
createIntegrationLaneForProposal, and the integrationResult state setter when
making the change.
🪄 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: 2c52c463-ee9d-464b-bb0e-019a54186137
📒 Files selected for processing (21)
apps/desktop/src/main/services/chat/agentChatService.tsapps/desktop/src/main/services/conflicts/conflictService.tsapps/desktop/src/main/services/ipc/registerIpc.tsapps/desktop/src/main/services/prs/prService.tsapps/desktop/src/main/services/state/kvDb.missionsMigration.test.tsapps/desktop/src/main/services/state/kvDb.tsapps/desktop/src/preload/global.d.tsapps/desktop/src/preload/preload.tsapps/desktop/src/renderer/components/chat/AgentChatComposer.tsxapps/desktop/src/renderer/components/chat/AgentChatPane.tsxapps/desktop/src/renderer/components/lanes/LanesPage.tsxapps/desktop/src/renderer/components/lanes/laneUtils.test.tsapps/desktop/src/renderer/components/lanes/laneUtils.tsapps/desktop/src/renderer/components/prs/CreatePrModal.tsxapps/desktop/src/renderer/components/prs/shared/PrAiResolverPanel.tsxapps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsxapps/desktop/src/shared/ipc.tsapps/desktop/src/shared/types/chat.tsapps/desktop/src/shared/types/conflicts.tsapps/desktop/src/shared/types/prs.tsapps/ios/ADE/Resources/DatabaseBootstrap.sql
| if (!prompt.length || !requestedModelId.length || !sourceLaneId.length) { | ||
| return fallback(); | ||
| } | ||
|
|
||
| let cwd = projectRoot; | ||
| try { | ||
| ({ laneWorktreePath: cwd } = resolveLaneLaunchContext({ | ||
| laneService, | ||
| laneId: sourceLaneId, | ||
| purpose: "name a lane from prompt", | ||
| })); | ||
| } catch { | ||
| cwd = projectRoot; |
There was a problem hiding this comment.
Remove the hard requirement on modelId/laneId before AI suggestion.
Line 4426 currently forces fallback unless prompt, modelId, and laneId are all present. That bypasses your own model fallback chain and cwd fallback path, so AI suggestion can be unintentionally disabled.
💡 Suggested fix
- if (!prompt.length || !requestedModelId.length || !sourceLaneId.length) {
+ if (!prompt.length) {
return fallback();
}
let cwd = projectRoot;
- try {
- ({ laneWorktreePath: cwd } = resolveLaneLaunchContext({
- laneService,
- laneId: sourceLaneId,
- purpose: "name a lane from prompt",
- }));
- } catch {
- cwd = projectRoot;
- }
+ if (sourceLaneId.length) {
+ try {
+ ({ laneWorktreePath: cwd } = resolveLaneLaunchContext({
+ laneService,
+ laneId: sourceLaneId,
+ purpose: "name a lane from prompt",
+ }));
+ } catch {
+ cwd = projectRoot;
+ }
+ }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/desktop/src/main/services/chat/agentChatService.ts` around lines 4426 -
4438, The current guard returns fallback() when requestedModelId or sourceLaneId
are empty, disabling AI suggestions; change the initial check to only require
prompt (i.e., remove requestedModelId/sourceLaneId from the if that calls
fallback()), keep the existing try/catch that attempts resolveLaneLaunchContext
to set cwd (laneWorktreePath) and fall back to projectRoot on error, and ensure
any later code that actually needs a model or lane uses the existing
model-fallback chain rather than this early return; refer to prompt,
requestedModelId, sourceLaneId, fallback(), resolveLaneLaunchContext and the
cwd/laneWorktreePath assignment when making the change.
| const sanitized = sanitizeAutoTitle(result.text.trim(), 56); | ||
| if (!sanitized) return fallback(); | ||
| return sanitized; | ||
| } catch (error) { |
There was a problem hiding this comment.
Enforce lane-safe normalization on model output before returning.
sanitizeAutoTitle(...) does not guarantee lane-safe characters across the full string (e.g., internal /, :), so this can return values that violate the lane naming contract while fallback returns a strict slug.
💡 Suggested fix
+ const normalizeLaneBase = (value: string): string | null => {
+ const normalized = value
+ .toLowerCase()
+ .replace(/[^a-z0-9 -]+/g, " ")
+ .replace(/\s+/g, " ")
+ .trim();
+ if (!normalized.length) return null;
+ const slug = normalized.replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
+ return slug.length ? slug.slice(0, 56) : null;
+ };
+
const sanitized = sanitizeAutoTitle(result.text.trim(), 56);
- if (!sanitized) return fallback();
- return sanitized;
+ const laneBase = sanitized ? normalizeLaneBase(sanitized) : null;
+ if (!laneBase) return fallback();
+ return laneBase;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/desktop/src/main/services/chat/agentChatService.ts` around lines 4476 -
4479, The returned auto-title must be run through the lane-safe normalizer and
validated before returning: after calling sanitizeAutoTitle(result.text.trim(),
56) run the project’s lane-safe normalizer (e.g., normalizeLaneName or
ensureLaneSafe) on the sanitized value and verify it produces a non-empty, valid
lane string; if the normalized result is empty/invalid, call fallback() instead;
update the return path in the function containing sanitizeAutoTitle(...) and the
existing fallback() usage to perform this post-normalization and validation.
| ipcMain.handle(IPC.agentChatSuggestLaneName, async (_event, arg: AgentChatSuggestLaneNameArgs): Promise<string> => { | ||
| const ctx = getCtx(); | ||
| return await ctx.agentChatService.suggestLaneNameFromPrompt(arg); | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 1) Confirm the new IPC handler currently forwards payload directly.
rg -n -C3 'IPC\.agentChatSuggestLaneName|suggestLaneNameFromPrompt\('
# 2) Inspect whether service-level validation exists for this arg type.
fd -i 'agentChatService.ts' --exec rg -n -C5 'suggestLaneNameFromPrompt|AgentChatSuggestLaneNameArgs' {}Repository: arul28/ADE
Length of output: 2780
🏁 Script executed:
# Find AgentChatSuggestLaneNameArgs type definition
rg -n 'AgentChatSuggestLaneNameArgs\s*=' --type ts --type tsxRepository: arul28/ADE
Length of output: 81
🏁 Script executed:
# Check if validation patterns exist at IPC boundary by looking at other handlers
rg -n 'ipcMain\.handle' apps/desktop/src/main/services/ipc/registerIpc.ts | head -20Repository: arul28/ADE
Length of output: 1730
🏁 Script executed:
# Look for requireRecord or parseRecord patterns to see if validation is a standard pattern
rg -n 'requireRecord|parseRecord' apps/desktop/src/main/services/ipc/registerIpc.ts | head -10Repository: arul28/ADE
Length of output: 677
🏁 Script executed:
# Check the service implementation more thoroughly to understand validation approach
sed -n '4414,4450p' apps/desktop/src/main/services/ipc/registerIpc.tsRepository: arul28/ADE
Length of output: 1465
🏁 Script executed:
# View requireRecord implementation
sed -n '3494,3510p' apps/desktop/src/main/services/ipc/registerIpc.tsRepository: arul28/ADE
Length of output: 690
🏁 Script executed:
# View full suggestLaneNameFromPrompt service method
sed -n '4414,4470p' apps/desktop/src/main/services/ipc/registerIpc.tsRepository: arul28/ADE
Length of output: 2163
🏁 Script executed:
# Find AgentChatSuggestLaneNameArgs type definition
rg -n 'AgentChatSuggestLaneNameArgs' -A 3 --type tsRepository: arul28/ADE
Length of output: 3567
🏁 Script executed:
# Get the full AgentChatSuggestLaneNameArgs type definition
sed -n '615,625p' apps/desktop/src/shared/types/chat.tsRepository: arul28/ADE
Length of output: 479
🏁 Script executed:
# Check if there are similar agent chat IPC handlers and how they're validated
rg -n 'ipcMain\.handle\(IPC\.agentChat' apps/desktop/src/main/services/ipc/registerIpc.ts -A 3 | head -40Repository: arul28/ADE
Length of output: 2037
🏁 Script executed:
# Look at patterns: how many IPC handlers use requireRecord vs direct typing
rg -n 'const parse.*Args.*=|ipcMain\.handle' apps/desktop/src/main/services/ipc/registerIpc.ts | grep -A1 'parse.*Args' | head -20Repository: arul28/ADE
Length of output: 427
Add runtime validation for IPC.agentChatSuggestLaneName payloads at the IPC boundary.
The handler accepts arg: AgentChatSuggestLaneNameArgs with static typing only. While the service layer performs String coercion on the received fields, runtime validation should occur at the IPC boundary before dispatch. This aligns with the established pattern in this file (e.g., agentChatCancelSteer uses parseAgentChatCancelSteerArgs) and hardens against malformed renderer payloads.
Suggested fix
+ const parseAgentChatSuggestLaneNameArgs = (value: unknown): AgentChatSuggestLaneNameArgs => {
+ const record = requireRecord(value, "Agent chat suggest lane name request");
+ if (typeof record.prompt !== "string" || !record.prompt.trim()) {
+ throw new Error("Agent chat suggest lane name prompt must be a non-empty string");
+ }
+ if (typeof record.modelId !== "string" || !record.modelId.trim()) {
+ throw new Error("Agent chat suggest lane name model ID must be a non-empty string");
+ }
+ if (typeof record.laneId !== "string" || !record.laneId.trim()) {
+ throw new Error("Agent chat suggest lane name lane ID must be a non-empty string");
+ }
+ return {
+ prompt: record.prompt.trim(),
+ modelId: record.modelId.trim(),
+ laneId: record.laneId.trim(),
+ } as AgentChatSuggestLaneNameArgs;
+ };
+
- ipcMain.handle(IPC.agentChatSuggestLaneName, async (_event, arg: AgentChatSuggestLaneNameArgs): Promise<string> => {
+ ipcMain.handle(IPC.agentChatSuggestLaneName, async (_event, arg: unknown): Promise<string> => {
const ctx = getCtx();
- return await ctx.agentChatService.suggestLaneNameFromPrompt(arg);
+ return await ctx.agentChatService.suggestLaneNameFromPrompt(parseAgentChatSuggestLaneNameArgs(arg));
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ipcMain.handle(IPC.agentChatSuggestLaneName, async (_event, arg: AgentChatSuggestLaneNameArgs): Promise<string> => { | |
| const ctx = getCtx(); | |
| return await ctx.agentChatService.suggestLaneNameFromPrompt(arg); | |
| }); | |
| const parseAgentChatSuggestLaneNameArgs = (value: unknown): AgentChatSuggestLaneNameArgs => { | |
| const record = requireRecord(value, "Agent chat suggest lane name request"); | |
| if (typeof record.prompt !== "string" || !record.prompt.trim()) { | |
| throw new Error("Agent chat suggest lane name prompt must be a non-empty string"); | |
| } | |
| if (typeof record.modelId !== "string" || !record.modelId.trim()) { | |
| throw new Error("Agent chat suggest lane name model ID must be a non-empty string"); | |
| } | |
| if (typeof record.laneId !== "string" || !record.laneId.trim()) { | |
| throw new Error("Agent chat suggest lane name lane ID must be a non-empty string"); | |
| } | |
| return { | |
| prompt: record.prompt.trim(), | |
| modelId: record.modelId.trim(), | |
| laneId: record.laneId.trim(), | |
| } as AgentChatSuggestLaneNameArgs; | |
| }; | |
| ipcMain.handle(IPC.agentChatSuggestLaneName, async (_event, arg: unknown): Promise<string> => { | |
| const ctx = getCtx(); | |
| return await ctx.agentChatService.suggestLaneNameFromPrompt(parseAgentChatSuggestLaneNameArgs(arg)); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/desktop/src/main/services/ipc/registerIpc.ts` around lines 3800 - 3803,
Add runtime validation at the IPC boundary for IPC.agentChatSuggestLaneName by
parsing the incoming payload before calling the service: implement or reuse a
validator named parseAgentChatSuggestLaneNameArgs that accepts the raw arg and
throws on invalid shape, invoke it inside the handler to produce a typed value,
then pass that validated result to
ctx.agentChatService.suggestLaneNameFromPrompt; update the handler signature to
accept the raw arg and remove direct reliance on static typing (keep references
to IPC.agentChatSuggestLaneName, AgentChatSuggestLaneNameArgs,
parseAgentChatSuggestLaneNameArgs, and suggestLaneNameFromPrompt to locate the
change).
| onInteractionModeChange: (mode) => patchParallelSlot(idx, { interactionMode: mode }), | ||
| onClaudeModeChange: (mode) => patchParallelSlot(idx, { claudePermissionMode: mode }), | ||
| onClaudePermissionModeChange: (mode) => patchParallelSlot(idx, { claudePermissionMode: mode }), |
There was a problem hiding this comment.
Keep Claude mode and interaction mode in sync for parallel lanes.
onClaudeModeChange only patches claudePermissionMode, but the launch path later reads slot.interactionMode when creating/sending Claude sessions. Selecting plan here can therefore still launch the lane with interactionMode: "default".
Suggested fix
- onClaudeModeChange: (mode) => patchParallelSlot(idx, { claudePermissionMode: mode }),
+ onClaudeModeChange: (mode) => patchParallelSlot(idx, {
+ interactionMode: mode === "plan" ? "plan" : "default",
+ claudePermissionMode: mode,
+ }),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/desktop/src/renderer/components/chat/AgentChatPane.tsx` around lines 828
- 830, onClaudeModeChange currently only sets claudePermissionMode via
patchParallelSlot(idx, { claudePermissionMode: mode }) but the launch path uses
slot.interactionMode to decide how to create/send Claude sessions; update
onClaudeModeChange to patch both claudePermissionMode and interactionMode (e.g.,
patchParallelSlot(idx, { claudePermissionMode: mode, interactionMode: mode }))
so selecting a Claude mode keeps the parallel slot's interactionMode in sync
with claudePermissionMode; mirror the same behavior for
onClaudePermissionModeChange if needed so both handlers maintain consistency.
| useEffect(() => { | ||
| if (!parallelChatMode) return; | ||
| if (parallelModelSlots.length >= 2) return; | ||
| setParallelModelSlots([ | ||
| cloneParallelSlotFromComposer({ | ||
| native: currentNativeControls, | ||
| modelId, | ||
| reasoningEffort, | ||
| executionMode, | ||
| }), | ||
| cloneParallelSlotFromComposer({ | ||
| native: currentNativeControls, | ||
| modelId, | ||
| reasoningEffort, | ||
| executionMode, | ||
| }), | ||
| ]); | ||
| }, [parallelChatMode, parallelModelSlots.length, currentNativeControls, modelId, reasoningEffort, executionMode]); |
There was a problem hiding this comment.
Don’t re-seed configured slots after a remove.
This effect runs any time the slot count drops below two. If the user removes one lane, the remaining configured slot gets replaced with two fresh clones from the composer, which wipes any per-lane model or permission changes they already made. Seed only on the initial enable (or when the list is empty), and guard the remove action instead of resetting from scratch.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/desktop/src/renderer/components/chat/AgentChatPane.tsx` around lines
1721 - 1738, The effect currently re-seeds lanes whenever
parallelModelSlots.length < 2, which wipes user changes on remove; change it to
only seed when enabling or when the list is empty: in the useEffect that
references parallelChatMode, parallelModelSlots, currentNativeControls, modelId,
reasoningEffort, executionMode, replace the guard "if (parallelModelSlots.length
>= 2) return" with "if (parallelModelSlots.length > 0) return" (or explicitly
"if (parallelModelSlots.length !== 0) return") so it only creates slots when
parallelChatMode becomes true and there are no slots; keep cloning via
cloneParallelSlotFromComposer with currentNativeControls, modelId,
reasoningEffort, executionMode and call setParallelModelSlots as before, and
ensure the dependency list still includes the relevant props; alternatively, if
you need to seed only on the transition from false->true, use a ref to track
previous parallelChatMode and only seed when prev was false and current is true
and parallelModelSlots.length === 0.
| <option value="">New integration branch</option> | ||
| {integrationMergeIntoOptions.map((lane) => ( | ||
| <option key={lane.id} value={lane.id} disabled={integrationSources.includes(lane.id)}> | ||
| {lane.name}{integrationSources.includes(lane.id) ? " (source)" : ""} | ||
| </option> | ||
| ))} | ||
| </select> | ||
| <div style={{ | ||
| marginTop: 6, | ||
| fontSize: 10, | ||
| fontFamily: "var(--font-sans)", | ||
| color: C.textMuted, | ||
| lineHeight: "14px", | ||
| }}> | ||
| When set, simulation includes conflicts against that lane's current HEAD. Commit prepares merges there instead of creating a new lane. | ||
| </div> |
There was a problem hiding this comment.
Rename this option/helper copy to lane language and state the action explicitly.
New integration branch conflicts with ADE's lane terminology, and Commit prepares merges there... doesn't say what action changes state. This is the main inline explanation of the new flow, so the copy should say exactly what ADE does on save.
💬 Suggested copy tweak
- <option value="">New integration branch</option>
+ <option value="">New integration lane</option>
- When set, simulation includes conflicts against that lane's current HEAD. Commit prepares merges there instead of creating a new lane.
+ When set, preview includes conflicts against the selected lane's current HEAD. When you save, ADE prepares merges on that lane instead of creating a new integration lane.As per coding guidelines Use 'lane' terminology for ADE worktrees/branches and Keep user-facing copy concrete and stateful: say what changed, what is blocked, and what the next action is.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <option value="">New integration branch</option> | |
| {integrationMergeIntoOptions.map((lane) => ( | |
| <option key={lane.id} value={lane.id} disabled={integrationSources.includes(lane.id)}> | |
| {lane.name}{integrationSources.includes(lane.id) ? " (source)" : ""} | |
| </option> | |
| ))} | |
| </select> | |
| <div style={{ | |
| marginTop: 6, | |
| fontSize: 10, | |
| fontFamily: "var(--font-sans)", | |
| color: C.textMuted, | |
| lineHeight: "14px", | |
| }}> | |
| When set, simulation includes conflicts against that lane's current HEAD. Commit prepares merges there instead of creating a new lane. | |
| </div> | |
| <option value="">New integration lane</option> | |
| {integrationMergeIntoOptions.map((lane) => ( | |
| <option key={lane.id} value={lane.id} disabled={integrationSources.includes(lane.id)}> | |
| {lane.name}{integrationSources.includes(lane.id) ? " (source)" : ""} | |
| </option> | |
| ))} | |
| </select> | |
| <div style={{ | |
| marginTop: 6, | |
| fontSize: 10, | |
| fontFamily: "var(--font-sans)", | |
| color: C.textMuted, | |
| lineHeight: "14px", | |
| }}> | |
| When set, preview includes conflicts against the selected lane's current HEAD. When you save, ADE prepares merges on that lane instead of creating a new integration lane. | |
| </div> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/desktop/src/renderer/components/prs/CreatePrModal.tsx` around lines 1541
- 1556, Update the user-facing copy to use "lane" terminology and explicitly
state the action on save: replace the option text "New integration branch" with
something like "New integration lane" (in the dropdown rendering inside
CreatePrModal where integrationMergeIntoOptions is mapped) and rewrite the
helper text below the select so it explicitly states what ADE will do on save —
e.g., "When set, simulation includes conflicts against that lane's current HEAD.
On save, ADE will prepare merges into that lane instead of creating a new lane."
Ensure the changes are applied to the JSX around integrationMergeIntoOptions and
integrationSources so the option label and the explanatory div reflect the new
lane-centric, stateful wording.
| {(() => { | ||
| const hasUnresolved = selectedProposal.overallOutcome !== "clean" && !allStepsResolved; | ||
| const isDisabled = commitBusy || selectedProposal.overallOutcome === "blocked" || hasUnresolved || !selectedProposalTargetLaneId; | ||
| const isDisabled = commitBusy || mergeIntoLaneBusy || selectedProposal.overallOutcome === "blocked" || hasUnresolved || !selectedProposalTargetLaneId; | ||
| return ( |
There was a problem hiding this comment.
Disable Create PR while re-simulation is replacing the proposal.
handleResimulate() writes a replacement proposal row and then deletes the current one, but isDisabled still ignores resimBusy. A fast click here can commit the stale proposal just before it is removed.
🐛 Suggested fix
- const isDisabled = commitBusy || mergeIntoLaneBusy || selectedProposal.overallOutcome === "blocked" || hasUnresolved || !selectedProposalTargetLaneId;
+ const isDisabled = commitBusy || resimBusy || mergeIntoLaneBusy || selectedProposal.overallOutcome === "blocked" || hasUnresolved || !selectedProposalTargetLaneId;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx` around
lines 2895 - 2898, The Create PR button's disabled logic (variable isDisabled in
IntegrationTab.tsx) doesn't account for resimulation activity so a fast click
can commit a proposal that's about to be replaced; update the isDisabled
expression (the same place that checks commitBusy, mergeIntoLaneBusy,
selectedProposal.overallOutcome, hasUnresolved, and
selectedProposalTargetLaneId) to also include resimBusy (or whatever boolean
tracks handleResimulate activity) so the button is disabled while
handleResimulate() is running.
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }), [prs, selectedPr, selectedPrId, mergeContextByPrId, laneById, mergeSourcesResolved, liveIntegrationLaneId, liveIntegrationRebaseNeed, liveSimulationLaneIds, resolverTargetLaneId, simulateResult, simulateBusy, simulateError, resolverOpen, proposalResolverConfig, deleteConfirm, deleteBusy, deleteCloseGh, hasConflicts, rebaseNeeds, rebaseNeedByLaneId, autoRebaseStatuses, setActiveTab, onSelectPr, onRefresh, proposals, proposalsLoaded, selectedProposal, selectedProposalId, selectedProposalRebaseLaneIds, selectedPrLiveModel, commitBusy, commitError, resimBusy, deleteProposalBusy, expandedPairKeys, resolutionState, activeWorkerStepId, createLaneBusy, resolvingLaneId, resolutionPanelDismissed, allStepsResolved, proposalLaneCards, proposalConflictingPairs, proposalConflictSteps, totalProposalConflictFiles, urlProposalId, conflictPairCountByLaneId, isLegacySequentialProposal, nextManualResolutionLaneId]); | ||
| }), [prs, selectedPr, selectedPrId, mergeContextByPrId, laneById, mergeSourcesResolved, liveIntegrationLaneId, liveIntegrationRebaseNeed, liveSimulationLaneIds, liveSimulationKey, resolverTargetLaneId, simulateResult, simulateBusy, simulateError, resolverOpen, proposalResolverConfig, deleteConfirm, deleteBusy, deleteCloseGh, hasConflicts, rebaseNeeds, rebaseNeedByLaneId, autoRebaseStatuses, setActiveTab, onSelectPr, onRefresh, proposals, proposalsLoaded, selectedProposal, selectedProposalId, selectedProposalRebaseLaneIds, selectedPrLiveModel, commitBusy, commitError, resimBusy, mergeIntoLaneBusy, deleteProposalBusy, expandedPairKeys, resolutionState, activeWorkerStepId, createLaneBusy, resolvingLaneId, resolutionPanelDismissed, allStepsResolved, proposalLaneCards, proposalConflictingPairs, proposalConflictSteps, totalProposalConflictFiles, urlProposalId, conflictPairCountByLaneId, isLegacySequentialProposal, nextManualResolutionLaneId]); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's check the file exists and get its line count
wc -l apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsxRepository: arul28/ADE
Length of output: 123
🏁 Script executed:
# Now let's read the area around lines 3168-3169 to see the memo definition
sed -n '3160,3180p' apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx | cat -nRepository: arul28/ADE
Length of output: 1500
🏁 Script executed:
# Let's get more context - read the full memo that likely starts before line 3168
sed -n '3100,3180p' apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx | cat -nRepository: arul28/ADE
Length of output: 3767
🏁 Script executed:
# Search for mergeIntoLaneDraft usage in the file
rg "mergeIntoLaneDraft" apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx -nRepository: arul28/ADE
Length of output: 297
🏁 Script executed:
# Also search for where detailPane is defined
rg "detailPane\s*=" apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx -n -A 2 -B 2Repository: arul28/ADE
Length of output: 299
🏁 Script executed:
# Let's see what's around line 2105 where mergeIntoLaneDraft is used
sed -n '2090,2120p' apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx | cat -nRepository: arul28/ADE
Length of output: 1871
🏁 Script executed:
# Also check what's at line 1269 to understand how mergeIntoLaneDraft is used
sed -n '1260,1320p' apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx | cat -nRepository: arul28/ADE
Length of output: 3304
🏁 Script executed:
# Let's look at the handleApplyMergeIntoTarget button to see how it uses the callback
sed -n '2130,2160p' apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx | cat -nRepository: arul28/ADE
Length of output: 1609
Add mergeIntoLaneDraft to the memo's dependency list.
The merge-target select element and its apply handler both depend on mergeIntoLaneDraft, but the memo doesn't include it in dependencies. This causes the UI to display stale values when the draft changes until an unrelated state update triggers a re-render.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/desktop/src/renderer/components/prs/tabs/IntegrationTab.tsx` around
lines 3168 - 3169, The memo's dependency array for the useMemo that renders
IntegrationTab is missing mergeIntoLaneDraft, causing stale UI; add
mergeIntoLaneDraft to that dependency list (the same array that currently
includes prs, selectedPr, selectedPrId, mergeContextByPrId, laneById, ...
nextManualResolutionLaneId) so the memo recalculates when the draft changes.
| originMissionId?: string | null; | ||
| originRunId?: string | null; | ||
| originLabel?: string | null; | ||
| additionalInstructions?: string | null; |
There was a problem hiding this comment.
Wire additionalInstructions through the renderer call path.
Line 411 extends the contract, but the provided call sites in apps/desktop/src/renderer/components/shared/conflictResolver/ResolverTerminalModal.tsx (lines 197-235 and 590-615) still omit additionalInstructions, so custom operator instructions won’t reach prepareResolverSession from that UI flow.
As per coding guidelines "Keep IPC contracts, preload types, shared types, and renderer usage in sync whenever an interface changes."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/desktop/src/shared/types/conflicts.ts` at line 411, The renderer call
sites in ResolverTerminalModal.tsx are not passing the newly-added
additionalInstructions field through to prepareResolverSession; update the UI
flow so that wherever prepareResolverSession (or the IPC wrapper that calls it)
is invoked from ResolverTerminalModal, you include the additionalInstructions
value from the component/state/props and forward it in the payload and any typed
IPC call. Concretely, locate the two invocation points in
ResolverTerminalModal.tsx that build the resolver request and add
additionalInstructions?: string | null to that object (and to any intermediary
handler/prop signatures) so the value flows into prepareResolverSession with the
correct type. Ensure TypeScript types remain consistent with the shared
conflicts type.
| alter table integration_proposals add column preferred_integration_lane_id text; | ||
|
|
||
| alter table integration_proposals add column merge_into_head_sha text; |
There was a problem hiding this comment.
Update iOS DAO/model mapping for the new columns.
Line 548 and Line 550 add new schema fields, but the provided snippets show apps/ios/ADE/Services/Database.swift (IntegrationProposalRow + fetchIntegrationProposals SELECT) and apps/ios/ADE/Models/RemoteModels.swift (IntegrationProposal) are not yet carrying preferred_integration_lane_id / merge_into_head_sha. This leaves the new data unsurfaced in iOS flows.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/ios/ADE/Resources/DatabaseBootstrap.sql` around lines 548 - 550, The DB
schema added two TEXT columns (preferred_integration_lane_id and
merge_into_head_sha); update the iOS model and DAO to surface them: add optional
String? properties named preferredIntegrationLaneId and mergeIntoHeadSha to
IntegrationProposal (RemoteModels.swift) and the corresponding fields to
IntegrationProposalRow (Database.swift), update the fetchIntegrationProposals
SELECT to include preferred_integration_lane_id and merge_into_head_sha and map
those columns into the new properties, and ensure any initializer/decoder and
database-to-model mapping code converts snake_case column names to the camelCase
property names and safely handles nulls.
Summary by CodeRabbit
New Features
Enhancements