Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
e348c0e
feat(providers): add Devin as a first-class provider
arul28 Sep 17, 2026
57ab006
feat(devin): use Cognition mark for all Devin surfaces, drop sidebar …
arul28 Sep 17, 2026
aa91065
ci(typecheck-desktop): raise Node heap to 8GB for desktop tsc
arul28 Sep 17, 2026
a62ccdc
fix(devin): second-round review fixes — pagination, pull repo check, …
arul28 Sep 17, 2026
be155fa
Merge branch 'main' into devin/1789603059-devin-provider
arul28 Sep 21, 2026
4383c66
fix(devin): keep cloud-turn completion pending until provably termina…
arul28 Sep 21, 2026
e8abd68
fix(devin): wire cloud commands into the remote router; address revie…
arul28 Sep 21, 2026
b81cdc7
fix(devin): verify() gates multi-org tokens too; v1 mirrors keep full…
arul28 Sep 21, 2026
b800673
fix(devin): page through all orgs during verify and org resolution
arul28 Sep 21, 2026
2bcb43b
chore: retrigger flaky desktop test shards
arul28 Sep 21, 2026
7813414
chore: retrigger flaky desktop test shard
arul28 Sep 21, 2026
775e2da
merge: main into devin-provider
arul28 Sep 21, 2026
86298f9
merge: main into devin-provider
arul28 Sep 21, 2026
0707361
fix(devin): disarm fleet delete on dismiss, clear stale org on v1, la…
arul28 Sep 21, 2026
b259b1a
fix(devin): verify lane branch is published before naming it to Devin
arul28 Sep 21, 2026
774f6f2
fix(devin): require remote lane branch to match HEAD before prompting…
arul28 Sep 21, 2026
b336e86
Merge remote-tracking branch 'origin/main' into devin/1789603059-devi…
arul28 Sep 21, 2026
80cc855
feat(devin): VM actions via devin CLI + platform picker on cloud create
arul28 Sep 21, 2026
9e7d6a1
fix(devin): platform on remote create, eventId-only remote dedupe, su…
arul28 Sep 21, 2026
bc9a729
fix(devin): make cloud echo dedupe durable across restarts
arul28 Sep 21, 2026
388146c
fix(devin): record the matched local fingerprint when consuming a clo…
arul28 Sep 21, 2026
6442c4c
fix(devin): verify PATs on non-enterprise accounts by probing the con…
arul28 Sep 21, 2026
73614ae
docs(devin): note org id entry for non-enterprise accounts
arul28 Sep 21, 2026
e6900e1
fix(devin): add org id field to Devin Cloud settings so non-enterpris…
arul28 Sep 21, 2026
5a7309e
fix(desktop): populate fleet Mine filter via /v3/self caller identity
arul28 Sep 21, 2026
3472136
fix(desktop): retry /v3/self after transient failures, drop stale clo…
arul28 Sep 21, 2026
ead40bf
fix(desktop): broaden attachment markup sniffing (BOM, comments, bare…
arul28 Sep 21, 2026
581a0ef
fix(desktop): flag markup only at document root so inline tags in tex…
arul28 Sep 21, 2026
5fc9583
fix(desktop): peel processing instructions at first > per HTML bogus-…
arul28 Sep 21, 2026
13da848
Merge remote-tracking branch 'origin/main' into devin/1789603059-devi…
arul28 Sep 22, 2026
5f7c7fa
fix(desktop): harden devin cloud pull/mirror edge cases
arul28 Sep 22, 2026
7ef66ca
chore: retrigger ci
arul28 Sep 22, 2026
44f8b7e
Merge remote-tracking branch 'origin/main' into devin/1789603059-devi…
arul28 Sep 22, 2026
dbf9cd9
chore: retrigger ci
arul28 Sep 22, 2026
9595bd1
fix(ade-cli): allow empty apiKey in remote setDevinCloudCredentials
arul28 Sep 22, 2026
32993a9
merge main into devin-provider branch
arul28 Sep 23, 2026
5da958a
fix(desktop): devin manifest entries, xai color, page-shape validatio…
arul28 Sep 23, 2026
689f683
merge main into devin-provider branch
arul28 Sep 23, 2026
9b45c86
fix merge fallout in chat header accessory
arul28 Sep 23, 2026
607f6ff
fix(desktop): devin review round — PR repo matching, env-key status, …
arul28 Sep 23, 2026
cba0e29
chore: retrigger ci (shard-8 flake)
arul28 Sep 23, 2026
6303a79
Merge remote-tracking branch 'origin/main' into devin/1789603059-devi…
arul28 Sep 23, 2026
8764952
fix(desktop): devin review — hard-fail repo-less cloud launch, XDG cr…
arul28 Sep 23, 2026
8416953
fix(sync): gate Devin credential writes with localOnly policy
arul28 Sep 23, 2026
90feb49
fix(devin): deliver cloud-send attachments and persist mirror state
arul28 Sep 23, 2026
9062afb
fix(devin): hold send slot across attachment uploads
arul28 Sep 23, 2026
80fcb1a
fix(devin): release send slot on any pre-dispatch failure
arul28 Sep 23, 2026
fd2f0ce
chore: retrigger CI for flaky modelManifestService shard
arul28 Sep 23, 2026
6cc88aa
Merge remote-tracking branch 'origin/main' into devin/1789603059-devi…
arul28 Sep 23, 2026
35d195e
fix(devin): adopt main's usage/account dialect surface after merge
arul28 Sep 23, 2026
d766060
fix(devin): close review gaps in creds, auth detection, and echo dedupe
arul28 Sep 23, 2026
507ea46
fix(devin): dedupe echoes on the delivered fingerprint, pin XDG override
arul28 Sep 23, 2026
9168888
fix(devin): let cleared pending echoes stay cleared
arul28 Sep 23, 2026
a1af8aa
Merge branch 'main' into devin/1789603059-devin-provider
arul28 Sep 24, 2026
f57c647
fix(desktop): devin cloud attachments, relink guard, handoff title, s…
arul28 Sep 24, 2026
37d78de
chore: retrigger CI for flaky agentChatService watchdog shard
arul28 Sep 24, 2026
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
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ jobs:
packages/chat-ui/node_modules
key: nm-v3-${{ hashFiles('apps/desktop/package-lock.json','apps/ade-cli/package-lock.json','apps/web/package-lock.json','apps/webhook-relay/package-lock.json','apps/push-relay/package-lock.json','packages/sdk/package-lock.json','packages/chat-ui/package-lock.json') }}
- run: cd apps/desktop && npm run typecheck
env:
# tsc on the desktop codebase sits near Node's default ~4GB heap;
# the lint script already needs --max-old-space-size=8192.
NODE_OPTIONS: --max-old-space-size=8192

typecheck-ade-cli:
needs: install
Expand Down
2 changes: 1 addition & 1 deletion apps/ade-cli/src/adeRpcServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ const TOOL_SPECS: ToolSpec[] = [
additionalProperties: false,
properties: {
laneId: { type: "string", minLength: 1 },
provider: { type: "string", enum: ["claude", "codex", "cursor", "droid", "opencode", "pi", "qwen", "kimi", "grok", "copilot", "shell"] },
provider: { type: "string", enum: ["claude", "codex", "cursor", "droid", "opencode", "pi", "qwen", "kimi", "grok", "copilot", "devin", "shell"] },
permissionMode: { type: "string", enum: [...AGENT_CHAT_PERMISSION_MODE_VALUES], default: "default" },
droidPermissionMode: { type: "string", enum: [...AGENT_CHAT_DROID_PERMISSION_MODE_VALUES] },
title: { type: "string" },
Expand Down
33 changes: 33 additions & 0 deletions apps/ade-cli/src/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ import { createLinearAccessTokenGetter, createLinearIngressService } from "../..
import { buildLinearAutomationDispatches } from "../../desktop/src/main/services/automations/linearAutomationDispatch";
import { createCursorCloudIngressService } from "../../desktop/src/main/services/automations/cursorCloudIngressService";
import { createCursorCloudFleetService } from "../../desktop/src/main/services/chat/cursorCloudFleetService";
import { createDevinCloudFleetService } from "../../desktop/src/main/services/chat/devinCloudFleetService";
import { buildCursorCloudAutomationDispatches } from "../../desktop/src/main/services/automations/cursorCloudAutomationDispatch";
import { openCursorCloudCredentialStore } from "../../desktop/src/main/services/chat/cursorCloudCreateOptions";
import { createAutomationSecretService } from "../../desktop/src/main/services/automations/automationSecretService";
Expand Down Expand Up @@ -372,6 +373,7 @@ export type AdeRuntime = {
agentChatService?: ReturnType<typeof createAgentChatService> | null;
chatLaunchService?: ChatLaunchService | null;
cursorCloudFleetService?: ReturnType<typeof createCursorCloudFleetService> | null;
devinCloudFleetService?: ReturnType<typeof createDevinCloudFleetService> | null;
prService?: ReturnType<typeof createPrService>;
prSummaryService?: ReturnType<typeof createPrSummaryService> | null;
fileService?: ReturnType<typeof createFileService> | null;
Expand Down Expand Up @@ -2026,6 +2028,35 @@ export async function createAdeRuntime(args: {
return { state: status.state, lastEventAt: status.lastEventAt };
},
});
const devinCloudFleetService = createDevinCloudFleetService({
projectRoot,
logger,
listDevinCloudSessions: (args) => aiIntegrationService.listDevinCloudSessions(args),
getDevinCloudSession: (devinSessionId) => aiIntegrationService.getDevinCloudSession(devinSessionId),
getDevinCloudCallerUserId: () => aiIntegrationService.getDevinCloudCallerUserId(),
laneService: {
list: (args) => laneService.list(args),
importBranch: (args) => laneService.importBranch(args),
},
listDevinCloudSessionLinks: async () => {
if (!agentChatService) throw new Error("Agent chat service not available.");
const sessions = await agentChatService.listSessions(undefined, { includeArchived: true });
return sessions
.filter((session) => Boolean(session.devinSessionId))
.sort((a, b) => Date.parse(b.lastActivityAt) - Date.parse(a.lastActivityAt))
.map((session) => ({
sessionId: session.sessionId,
devinSessionId: session.devinSessionId ?? "",
laneId: session.laneId,
title: session.title ?? null,
}))
.filter((link) => link.devinSessionId.length > 0);
},
openDevinCloudChat: (args) => {
if (!agentChatService) throw new Error("Agent chat service not available.");
return agentChatService.openDevinCloudChat(args);
},
});
const configReloadService = createConfigReloadService({
paths: {
sharedPath: adeProjectService.paths.sharedConfigPath,
Expand Down Expand Up @@ -2467,6 +2498,7 @@ export async function createAdeRuntime(args: {
agentChatService,
chatLaunchService,
cursorCloudFleetService,
devinCloudFleetService,
pushPublisherService,
ctoStateService,
ctoMemoryService,
Expand Down Expand Up @@ -2634,6 +2666,7 @@ export async function createAdeRuntime(args: {
agentChatService,
chatLaunchService,
cursorCloudFleetService,
devinCloudFleetService,
ctoStateService,
ctoMemoryService,
ctoVoiceCallService,
Expand Down
2 changes: 1 addition & 1 deletion apps/ade-cli/src/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3858,7 +3858,7 @@ describe("ADE CLI", () => {
"shell",
"--print-config",
]),
).toThrow(/provider must be one of claude, codex, cursor, droid, opencode, pi, qwen, kimi, grok, or copilot/);
).toThrow(/provider must be one of claude, codex, cursor, droid, opencode, pi, qwen, kimi, grok, copilot, or devin/);
});

it("accepts a mis-cased provider when starting a CLI session", () => {
Expand Down
16 changes: 16 additions & 0 deletions apps/ade-cli/src/services/agentRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,22 @@ export const AGENT_CLI_REGISTRY: AgentCliDescriptor[] = [
/\bgh[_ ]token\b.*\b(invalid|missing|not found|not set|required|unauthorized|must be set)\b/i,
],
},
{
agent: "devin",
displayName: "Devin CLI",
binaryNames: ["devin"],
installCommand: "curl -fsSL https://cli.devin.ai/install.sh | bash",
authCommand: "devin auth login",
missingErrorPatterns: [
/\bdevin\b.*\b(command not found|not recognized|not found|enoent)\b/i,
/\bspawn\s+devin\s+enoent\b/i,
],
notAuthErrorPatterns: [
/\bdevin\b.*\b(not logged in|not authenticated|unauthorized|authentication failed|login required|no credentials|sign\s*in)\b/i,
/\brun\s+[`'"]?devin\s+auth\s+login[`'"]?/i,
/\bwindsurf[_ ]api[_ ]key\b.*\b(invalid|missing|not found|not set|required|unauthorized|must be set)\b/i,
],
},
];

function descriptorMatchesPreferred(descriptor: AgentCliDescriptor, preferredAgent: string | null | undefined): boolean {
Expand Down
7 changes: 7 additions & 0 deletions apps/ade-cli/src/services/sync/syncHostService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6380,6 +6380,10 @@ describe("CTO-gated Linear sync commands", () => {
"ai.cursorCloudResolveLane",
"ai.cursorCloudPullIntoLane",
"ai.cursorCloudStopRun",
"ai.getDevinCloudFleet",
"ai.pullDevinCloudSessionIntoLane",
"ai.openDevinCloudChat",
"ai.getDevinCloudAuthStatus",
"chat.listPromptStashes",
"chat.createPromptStash",
"chat.deletePromptStash",
Expand Down Expand Up @@ -6414,6 +6418,8 @@ describe("CTO-gated Linear sync commands", () => {
// both are host state mutations refused to read-only viewers.
"ai.cursorCloudResolveLane",
"ai.cursorCloudPullIntoLane",
// Pulling a Devin session's PR head mutates lane worktrees too.
"ai.pullDevinCloudSessionIntoLane",
// Resuming spends a provider turn, so it is a host mutation a
// read-only viewer never gets to make.
"chat.resumeUsageLimitNow",
Expand All @@ -6431,6 +6437,7 @@ describe("CTO-gated Linear sync commands", () => {
"ai.cursorCloudStopRun",
]);
const controllerAllowedActions = new Set<string>([
"ai.pullDevinCloudSessionIntoLane",
"ai.createCursorCloudRun",
"ai.archiveCursorCloudAgent",
"ai.unarchiveCursorCloudAgent",
Expand Down
3 changes: 3 additions & 0 deletions apps/ade-cli/src/services/sync/syncHostService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ import type { AccountAttestationConfig } from "../account/sharedAccountAuthServi
import { verifyClerkAccountAttestation } from "../account/accountAttestationVerifier";
import type { createAgentChatService } from "../../../../desktop/src/main/services/chat/agentChatService";
import type { createCursorCloudFleetService } from "../../../../desktop/src/main/services/chat/cursorCloudFleetService";
import type { createDevinCloudFleetService } from "../../../../desktop/src/main/services/chat/devinCloudFleetService";
import type { createAiIntegrationService } from "../../../../desktop/src/main/services/ai/aiIntegrationService";
import type { createCtoStateService } from "../../../../desktop/src/main/services/cto/ctoStateService";
import type { CtoMemoryService } from "../../../../desktop/src/main/services/cto/ctoMemoryService";
Expand Down Expand Up @@ -1152,6 +1153,7 @@ type SyncHostServiceArgs = {
agentChatService?: ReturnType<typeof createAgentChatService>;
chatLaunchService?: ChatLaunchService | null;
cursorCloudFleetService?: ReturnType<typeof createCursorCloudFleetService> | null;
devinCloudFleetService?: ReturnType<typeof createDevinCloudFleetService> | null;
personalChatScope?: Pick<
PersonalChatScopeContract,
"call" | "streamEvents" | "transcriptPath" | "isTurnActive"
Expand Down Expand Up @@ -2278,6 +2280,7 @@ export function createSyncHostService(args: SyncHostServiceArgs) {
agentChatService: args.agentChatService,
chatLaunchService: args.chatLaunchService,
cursorCloudFleetService: args.cursorCloudFleetService,
devinCloudFleetService: args.devinCloudFleetService,
personalChatScope: args.personalChatScope,
aiIntegrationService: args.aiIntegrationService,
accountSettingsStore: args.accountSettingsStore,
Expand Down
Loading
Loading