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
18 changes: 18 additions & 0 deletions apps/array/src/constants/oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,28 @@ export const POSTHOG_DEV_CLIENT_ID = "DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ";
export const OAUTH_PORT = 8237;

export const OAUTH_SCOPES = [
// Array app needs
"user:read",
"project:read",
"task:write",
"integration:read",
"introspection",
"dashboard:read",
"error_tracking:read",
"event_definition:read",
"experiment:read",
"feature_flag:read",
"insight:read",
"organization:read",
"property_definition:read",
"query:read",
"survey:read",
"warehouse_table:read",
"dashboard:write",
"experiment:write",
"feature_flag:write",
"insight:write",
"survey:write",
];

// Token refresh settings
Expand Down
5 changes: 5 additions & 0 deletions apps/array/src/main/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ contextBridge.exposeInMainWorld("electronAPI", {
sdkSessionId?: string;
}): Promise<{ sessionId: string; channel: string } | null> =>
ipcRenderer.invoke("agent-reconnect", params),
agentTokenRefresh: async (
taskRunId: string,
newToken: string,
): Promise<void> =>
ipcRenderer.invoke("agent-token-refresh", taskRunId, newToken),
onAgentEvent: (
channel: string,
listener: (payload: unknown) => void,
Expand Down
64 changes: 62 additions & 2 deletions apps/array/src/main/services/session-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,13 @@ export interface PostHogCredentials {
projectId: number;
}

interface AcpMcpServer {
name: string;
type: "http";
url: string;
headers: Array<{ name: string; value: string }>;
}

export interface SessionConfig {
taskId: string;
taskRunId: string; // THE session identifier everywhere
Expand Down Expand Up @@ -146,6 +153,7 @@ function getClaudeCliPath(): string {

export class SessionManager {
private sessions = new Map<string, ManagedSession>();
private sessionTokens = new Map<string, string>();
private getMainWindow: () => BrowserWindow | null;
private onLog: OnLogCallback;

Expand All @@ -154,6 +162,45 @@ export class SessionManager {
this.onLog = onLog;
}

public updateSessionToken(taskRunId: string, newToken: string): void {
this.sessionTokens.set(taskRunId, newToken);
log.info("Session token updated", { taskRunId });
}

private getSessionToken(taskRunId: string, fallback: string): string {
return this.sessionTokens.get(taskRunId) || fallback;
}

private buildMcpServers(
credentials: PostHogCredentials,
taskRunId: string,
): AcpMcpServer[] {
const servers: AcpMcpServer[] = [];

const mcpUrl = this.getPostHogMcpUrl(credentials.apiHost);
const token = this.getSessionToken(taskRunId, credentials.apiKey);

servers.push({
name: "posthog",
type: "http",
url: mcpUrl,
headers: [{ name: "Authorization", value: `Bearer ${token}` }],
});

return servers;
}

private getPostHogMcpUrl(apiHost: string): string {
if (
apiHost.includes("localhost") ||
apiHost.includes("127.0.0.1") ||
!app.isPackaged
) {
return "http://localhost:8787/mcp";
}
return "https://mcp.posthog.com/mcp";
}

async createSession(config: SessionConfig): Promise<ManagedSession> {
const session = await this.getOrCreateSession(config, false);
if (!session) {
Expand Down Expand Up @@ -209,13 +256,15 @@ export class SessionManager {
clientCapabilities: {},
});

const mcpServers = this.buildMcpServers(credentials, taskRunId);

if (isReconnect) {
// Use our custom extension method to resume without replaying history.
// Client fetches history from S3 directly.
await connection.extMethod("_posthog/session/resume", {
sessionId: taskRunId,
cwd: repoPath,
mcpServers: [],
mcpServers,
_meta: {
...(logUrl && {
persistence: { taskId, runId: taskRunId, logUrl },
Expand All @@ -226,7 +275,7 @@ export class SessionManager {
} else {
await connection.newSession({
cwd: repoPath,
mcpServers: [],
mcpServers,
_meta: { sessionId: taskRunId },
});
}
Expand Down Expand Up @@ -588,4 +637,15 @@ export function registerAgentIpc(
return session ? toSessionResponse(session) : null;
},
);

ipcMain.handle(
"agent-token-refresh",
async (
_event: IpcMainInvokeEvent,
taskRunId: string,
newToken: string,
): Promise<void> => {
sessionManager.updateSessionToken(taskRunId, newToken);
},
);
}
Loading