Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .ade/ade.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,22 @@ stackButtons: []
testSuites: []
laneOverlayPolicies: []
automations: []
ai:
features:
narratives: true
conflict_proposals: true
commit_messages: true
pr_descriptions: true
terminal_summaries: true
memory_consolidation: true
mission_planning: true
orchestrator: true
initial_context: true
featureModelOverrides:
commit_messages: anthropic/claude-haiku-4-5
pr_descriptions: openai/gpt-5.3-codex-spark
terminal_summaries: openai/gpt-5.3-codex-spark
chat:
autoTitleEnabled: true
autoTitleModelId: openai/gpt-5.3-codex-spark
autoTitleRefreshOnComplete: true
6 changes: 6 additions & 0 deletions apps/desktop/src/main/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { app, BrowserWindow, nativeImage, shell } from "electron";
import path from "node:path";
type NodePtyType = typeof import("node-pty");

Check warning on line 3 in apps/desktop/src/main/main.ts

View workflow job for this annotation

GitHub Actions / lint-desktop

`import()` type annotations are forbidden
import { registerIpc } from "./services/ipc/registerIpc";
import { createFileLogger } from "./services/logging/logger";
import { openKvDb } from "./services/state/kvDb";
Expand Down Expand Up @@ -796,6 +796,7 @@
aiIntegrationService,
projectConfigService,
conflictService,
autoRebaseService,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

AUTO_FILE="$(fd 'autoRebaseService.ts$' apps/desktop/src/main/services/lanes | head -n 1)"
if [[ -z "${AUTO_FILE}" ]]; then
  exit 1
fi

printf '== autoRebaseService timers / teardown ==\n'
rg -n -C3 'setTimeout|setInterval|clearTimeout|clearInterval|debounce|dispose|stop' "$AUTO_FILE"

printf '\n== project context teardown ==\n'
sed -n '2340,2475p' apps/desktop/src/main/main.ts

Repository: arul28/ADE

Length of output: 3731


🏁 Script executed:

# Find the autoRebaseService file and check for dispose/stop method definitions
fd 'autoRebaseService.ts$' apps/desktop/src/main/services/lanes --exec sh -c '
  echo "=== Full autoRebaseService structure ==="
  wc -l "$1"
  echo ""
  echo "=== Method/function definitions ==="
  rg -n "^\s*(async\s+)?(function|export|const|declare)\s+" "$1" | head -20
  echo ""
  echo "=== dispose/stop method search ==="
  rg -n "dispose|stop" "$1" | grep -E "(function|const|async|=>)" | head -10
' sh {} \;

Repository: arul28/ADE

Length of output: 1614


🏁 Script executed:

# Also check AppContext type definition to see if autoRebaseService is typed
rg -n "autoRebaseService" apps/desktop/src/main/main.ts | head -15

Repository: arul28/ADE

Length of output: 490


🏁 Script executed:

# Check the createAutoRebaseService export and return type
rg -n "export.*createAutoRebaseService|function createAutoRebaseService" apps/desktop/src/main/services/lanes/autoRebaseService.ts -A 30

Repository: arul28/ADE

Length of output: 956


🏁 Script executed:

# Check if the service has any cleanup/disposal methods in its interface
rg -n "dispose|stop|cleanup|teardown|unsubscribe|off|removeListener" apps/desktop/src/main/services/lanes/autoRebaseService.ts

Repository: arul28/ADE

Length of output: 259


🏁 Script executed:

# Check how autoRebaseService is set to null in the context cleanup (line 2276)
sed -n '2270,2285p' apps/desktop/src/main/main.ts

Repository: arul28/ADE

Length of output: 524


🏁 Script executed:

# Get the full createAutoRebaseService function return statement
sed -n '68,474p' apps/desktop/src/main/services/lanes/autoRebaseService.ts | tail -100

Repository: arul28/ADE

Length of output: 3377


🏁 Script executed:

# Search for return statements in autoRebaseService
rg -n "return {" apps/desktop/src/main/services/lanes/autoRebaseService.ts -A 20

Repository: arul28/ADE

Length of output: 133


Add cleanup hook for autoRebaseService timers and wire into disposeContextResources().

The service maintains a queueByRoot map with pending setTimeout calls but exports no dispose/stop method. Without cleanup, timers can fire after the lane project context closes—potentially writing to the database after db.close() or operating on stale state during project switches.

Add a cleanup method to createAutoRebaseService that clears all pending timers (iterate queueByRoot and clearTimeout each), export it, and call it in disposeContextResources() alongside the other service disposal calls.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/main.ts` at line 824, createAutoRebaseService currently
leaves pending timers in its internal queueByRoot map and exports no cleanup;
add a dispose/stop method on the object returned by createAutoRebaseService that
iterates queueByRoot, calls clearTimeout on each timer id, and clears the map to
prevent callbacks after context shutdown. Export/use that new method from
wherever autoRebaseService is created and call it from disposeContextResources()
alongside the other service disposers (so timers are cleared before
db.close()/context teardown). Ensure the method name (e.g., dispose or stop) is
added to the autoRebaseService interface so callers can invoke it.

rebaseSuggestionService,
onHotRefreshChanged: () => {
prPollingServiceRef?.poke();
Expand Down Expand Up @@ -2329,6 +2330,11 @@
} catch {
// ignore
}
try {
ctx.autoRebaseService?.dispose();
} catch {
// ignore
}
try {
ctx.automationIngressService?.dispose();
} catch {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
augmentPathWithKnownCliDirs,
resolveExecutableFromKnownLocations,
Expand All @@ -26,6 +26,7 @@ describe("cliExecutableResolver", () => {
let tempRoot: string | null = null;

afterEach(() => {
vi.restoreAllMocks();
setPlatform(originalPlatform);
if (tempRoot) {
fs.rmSync(tempRoot, { recursive: true, force: true });
Expand All @@ -41,6 +42,20 @@ describe("cliExecutableResolver", () => {
fs.mkdirSync(homeDir, { recursive: true });
fs.writeFileSync(path.join(homeDir, ".npmrc"), "prefix=~/.npm-global\n", "utf8");

// Hide system-installed codex so it doesn't win the known-dirs race.
const realStatSync = fs.statSync;
vi.spyOn(fs, "statSync").mockImplementation(((p: fs.PathLike, opts?: any) => {
const normalizedCandidate = path.normalize(String(p));
const normalizedTempRoot = path.normalize(tempRoot!);
const candidateBase = path.parse(normalizedCandidate).name.toLowerCase();
if (candidateBase === "codex" && !normalizedCandidate.startsWith(normalizedTempRoot)) {
const err: NodeJS.ErrnoException = new Error("ENOENT");
err.code = "ENOENT";
throw err;
}
return realStatSync(normalizedCandidate, opts);
}) as typeof fs.statSync);

const env = {
HOME: homeDir,
PATH: "/usr/bin:/bin",
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src/main/services/ai/tools/systemPrompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export function buildCodingAgentSystemPrompt(args: {

return [
`You are ADE's software engineering agent working in ${args.cwd}.`,
"This session is bound to that worktree. Read, edit, and run commands only inside this path unless ADE explicitly relaunches you in a different lane.",
"",
"## Mission",
describeMode(mode),
Expand Down
Loading
Loading