diff --git a/integration-tests/src/mocks/claude-server.ts b/integration-tests/src/mocks/claude-server.ts index a1b2f93e..f25bdd1c 100644 --- a/integration-tests/src/mocks/claude-server.ts +++ b/integration-tests/src/mocks/claude-server.ts @@ -75,7 +75,7 @@ export class MockClaudeServer { }); // Health check - this.app.get("/health", (req, res) => { + this.app.get("/health", (_req, res) => { res.json({ status: "ok", mock: true }); }); } diff --git a/integration-tests/src/mocks/slack-server.ts b/integration-tests/src/mocks/slack-server.ts index 48b16e3c..54b009c7 100644 --- a/integration-tests/src/mocks/slack-server.ts +++ b/integration-tests/src/mocks/slack-server.ts @@ -1,5 +1,5 @@ import express from "express"; -import { EventEmitter } from "events"; +import { EventEmitter } from "node:events"; interface SlackMessage { ts: string; @@ -97,7 +97,7 @@ export class MockSlackServer extends EventEmitter { }); // Mock auth.test - this.app.post("/api/auth.test", (req, res) => { + this.app.post("/api/auth.test", (_req, res) => { res.json({ ok: true, url: "https://test-workspace.slack.com/", diff --git a/modules/github/actions.ts b/modules/github/actions.ts index 9e157c4e..7692bc55 100644 --- a/modules/github/actions.ts +++ b/modules/github/actions.ts @@ -169,4 +169,4 @@ export async function generateGitHubActionButtons( // Return undefined on error - this will result in no action buttons being added return undefined; } -} \ No newline at end of file +} diff --git a/modules/github/errors.ts b/modules/github/errors.ts index cf249816..17feb2a6 100644 --- a/modules/github/errors.ts +++ b/modules/github/errors.ts @@ -22,4 +22,4 @@ export class GitHubRepositoryError extends BaseError { username: this.username, }; } -} \ No newline at end of file +} diff --git a/modules/github/handlers.ts b/modules/github/handlers.ts index 71ac272d..d63fcd7b 100644 --- a/modules/github/handlers.ts +++ b/modules/github/handlers.ts @@ -433,4 +433,4 @@ export async function getUserGitHubInfo(userId: string): Promise<{ logger.error(`Failed to get GitHub info for user ${userId}:`, error); return { token: null, username: null }; } -} \ No newline at end of file +} diff --git a/modules/github/index.ts b/modules/github/index.ts index fa504053..b1120dff 100644 --- a/modules/github/index.ts +++ b/modules/github/index.ts @@ -1,8 +1,16 @@ -import { z } from 'zod'; -import type { HomeTabModule, WorkerModule, OrchestratorModule, DispatcherModule, SessionContext, ActionButton, ThreadContext } from '../types'; -import { GitHubRepositoryManager } from './repository-manager'; -import { handleGitHubConnect, handleGitHubLogout, getUserGitHubInfo } from './handlers'; -import { generateGitHubAuthUrl } from './utils'; +import { z } from "zod"; +import type { + HomeTabModule, + WorkerModule, + OrchestratorModule, + DispatcherModule, + SessionContext, + ActionButton, + ThreadContext, +} from "../types"; +import { GitHubRepositoryManager } from "./repository-manager"; +import { getUserGitHubInfo } from "./handlers"; +import { generateGitHubAuthUrl } from "./utils"; // GitHub configuration schema (module-specific) export const GitHubConfigSchema = z.object({ @@ -36,8 +44,10 @@ export function loadGitHubConfig(): GitHubConfig { }); } -export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorModule, DispatcherModule { - name = 'github'; +export class GitHubModule + implements HomeTabModule, WorkerModule, OrchestratorModule, DispatcherModule +{ + name = "github"; private repoManager?: GitHubRepositoryManager; isEnabled(): boolean { @@ -46,7 +56,7 @@ export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorMo async init(): Promise { if (!this.isEnabled()) return; - + const config = loadGitHubConfig(); this.repoManager = new GitHubRepositoryManager( config, @@ -59,7 +69,7 @@ export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorMo const { token, username } = await getUserGitHubInfo(userId); const isGitHubConnected = !!token; - + if (!isGitHubConnected) { const authUrl = generateGitHubAuthUrl(userId); return [ @@ -88,12 +98,18 @@ export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorMo ]; } - const userRepo = await this.repoManager.getUserRepository(username!, userId); - + const userRepo = await this.repoManager.getUserRepository( + username!, + userId + ); + if (userRepo) { const repoUrl = userRepo.repositoryUrl.replace(/\.git$/, ""); - const repoDisplayName = repoUrl.replace(/^https?:\/\/(www\.)?github\.com\//, ""); - + const repoDisplayName = repoUrl.replace( + /^https?:\/\/(www\.)?github\.com\//, + "" + ); + return [ { type: "section", @@ -109,7 +125,7 @@ export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorMo }, ]; } - + return [ { type: "section", @@ -144,26 +160,24 @@ export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorMo ]; } - async handleHomeTabAction(actionId: string, userId: string, value?: any): Promise { - // Home tab actions are handled by the dispatcher action handler - // This method is called from the dispatcher for module-specific actions - } - - async initWorkspace(config: { repositoryUrl?: string; workspaceDir?: string }): Promise { + async initWorkspace(config: { + repositoryUrl?: string; + workspaceDir?: string; + }): Promise { if (!config.repositoryUrl || !config.workspaceDir) return; - + // Clone repository if not already present const repoName = this.extractRepoName(config.repositoryUrl); const targetDir = `${config.workspaceDir}/${repoName}`; - + // Check if repo already exists try { - const fs = await import('fs'); + const fs = await import("node:fs"); if (!fs.existsSync(targetDir)) { - const { execSync } = await import('child_process'); - execSync(`git clone ${config.repositoryUrl} ${targetDir}`, { - stdio: 'inherit', - cwd: config.workspaceDir + const { execSync } = await import("node:child_process"); + execSync(`git clone ${config.repositoryUrl} ${targetDir}`, { + stdio: "inherit", + cwd: config.workspaceDir, }); } } catch (error) { @@ -195,9 +209,12 @@ export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorMo ]; } - async buildEnvVars(userId: string, baseEnv: Record): Promise> { + async buildEnvVars( + userId: string, + baseEnv: Record + ): Promise> { const { token, username } = await getUserGitHubInfo(userId); - + if (token && username) { return { ...baseEnv, @@ -205,7 +222,7 @@ export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorMo GITHUB_USER: username, }; } - + return baseEnv; } @@ -241,7 +258,7 @@ export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorMo */ async isGitHubCLIAuthenticated(workingDir: string): Promise { try { - const { execSync } = await import('child_process'); + const { execSync } = await import("node:child_process"); execSync("gh auth status", { cwd: workingDir, stdio: "pipe", @@ -264,7 +281,7 @@ export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorMo return []; } - const { generateGitHubActionButtons } = await import('./actions'); + const { generateGitHubActionButtons } = await import("./actions"); const buttons = await generateGitHubActionButtons( context.userId, context.gitBranch, @@ -275,38 +292,50 @@ export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorMo context.slackClient ); - return buttons?.map(button => ({ - text: button.text?.text || '', - action_id: button.action_id, - style: button.style, - value: button.value - })) || []; + return ( + buttons?.map((button) => ({ + text: button.text?.text || "", + action_id: button.action_id, + style: button.style, + value: button.value, + })) || [] + ); } - async handleAction(actionId: string, userId: string, context: any): Promise { + async handleAction( + actionId: string, + userId: string, + context: any + ): Promise { // Handle GitHub-specific actions switch (actionId) { - case "github_login": - const { handleGitHubConnect } = await import('./handlers'); + case "github_login": { + const { handleGitHubConnect } = await import("./handlers"); await handleGitHubConnect(userId, context.channelId, context.client); return true; - - case "github_logout": - const { handleGitHubLogout } = await import('./handlers'); + } + + case "github_logout": { + const { handleGitHubLogout } = await import("./handlers"); await handleGitHubLogout(userId, context.client); // Update home tab after logout - delegate back to action handler if (context.updateAppHome) { await context.updateAppHome(userId, context.client); } return true; - + } + case "open_repository_modal": // This is handled by repository-modal-utils which should also be moved to module return false; // Let dispatcher handle for now - + default: // Check if it's a GitHub-specific action (prefixed with github_ or contains repo operations) - if (actionId.startsWith('github_') || actionId.includes('pr_') || actionId.includes('view_pr_')) { + if ( + actionId.startsWith("github_") || + actionId.includes("pr_") || + actionId.includes("view_pr_") + ) { // This is a GitHub action but not one we handle directly return false; } @@ -317,9 +346,13 @@ export class GitHubModule implements HomeTabModule, WorkerModule, OrchestratorMo getRepositoryManager(): GitHubRepositoryManager | undefined { return this.repoManager; } + + async getUserInfo(userId: string) { + return getUserGitHubInfo(userId); + } } -export * from './repository-manager'; -export * from './handlers'; -export * from './utils'; -export * from './errors'; \ No newline at end of file +export * from "./repository-manager"; +export * from "./handlers"; +export * from "./utils"; +export * from "./errors"; diff --git a/modules/github/repository-manager.ts b/modules/github/repository-manager.ts index 3df07483..ad0b61f9 100644 --- a/modules/github/repository-manager.ts +++ b/modules/github/repository-manager.ts @@ -7,8 +7,8 @@ const logger = createLogger("github-module"); // Import from shared package and local module import { getDbPool } from "@peerbot/shared"; -import { GitHubRepositoryError } from './errors'; -import type { GitHubConfig } from './index'; +import { GitHubRepositoryError } from "./errors"; +import type { GitHubConfig } from "./index"; export interface GitHubModuleConfig extends GitHubConfig { // All config is already in the base GitHubConfig type @@ -316,4 +316,4 @@ export class GitHubRepositoryManager { return null; } } -} \ No newline at end of file +} diff --git a/modules/github/utils.ts b/modules/github/utils.ts index 1a81c321..4999fff7 100644 --- a/modules/github/utils.ts +++ b/modules/github/utils.ts @@ -8,4 +8,4 @@ export function generateGitHubAuthUrl(userId: string): string { const baseUrl = process.env.INGRESS_URL || "http://localhost:8080"; return `${baseUrl}/api/github/oauth/authorize?user_id=${userId}`; -} \ No newline at end of file +} diff --git a/modules/github/workspace.ts b/modules/github/workspace.ts index 805bc421..0a0bdf2c 100644 --- a/modules/github/workspace.ts +++ b/modules/github/workspace.ts @@ -39,8 +39,7 @@ export class GitHubWorkspaceManager { async setupGitHubWorkspace( repositoryUrl: string, userDirectory: string, - username: string, - sessionKey?: string + username: string ): Promise { try { logger.info(`Setting up GitHub workspace for ${username}...`); @@ -54,7 +53,10 @@ export class GitHubWorkspaceManager { } // Get repository info - const repository = await this.getRepositoryInfo(userDirectory, repositoryUrl); + const repository = await this.getRepositoryInfo( + userDirectory, + repositoryUrl + ); return { baseDirectory: this.config.baseDirectory, @@ -117,7 +119,9 @@ export class GitHubWorkspaceManager { logger.info("Git configuration completed"); } catch (error) { - throw new Error(`Failed to setup git configuration for ${username}: ${error}`); + throw new Error( + `Failed to setup git configuration for ${username}: ${error}` + ); } } @@ -158,7 +162,10 @@ export class GitHubWorkspaceManager { /** * Create a new branch for the session */ - async createSessionBranch(userDirectory: string, sessionKey: string): Promise { + async createSessionBranch( + userDirectory: string, + sessionKey: string + ): Promise { try { const branchName = `claude/${sessionKey.replace(/\./g, "-")}`; @@ -170,7 +177,9 @@ export class GitHubWorkspaceManager { await execAsync(`git checkout "${branchName}"`, { cwd: userDirectory, }); - logger.info(`Session branch ${branchName} already exists locally, checked out`); + logger.info( + `Session branch ${branchName} already exists locally, checked out` + ); // Pull latest changes from remote to preserve previous work try { @@ -222,14 +231,20 @@ export class GitHubWorkspaceManager { return branchName; } catch (error) { - throw new Error(`Failed to create session branch for ${sessionKey}: ${error}`); + throw new Error( + `Failed to create session branch for ${sessionKey}: ${error}` + ); } } /** * Commit and push changes */ - async commitAndPush(userDirectory: string, branch: string, message: string): Promise { + async commitAndPush( + userDirectory: string, + branch: string, + message: string + ): Promise { try { // Add all changes await execAsync("git add .", { cwd: userDirectory }); @@ -237,8 +252,12 @@ export class GitHubWorkspaceManager { // Check if there are changes to commit let hasUnstagedChanges = false; try { - await execAsync("git diff --cached --exit-code", { cwd: userDirectory }); - logger.info("No staged changes to commit - checking for unpushed commits"); + await execAsync("git diff --cached --exit-code", { + cwd: userDirectory, + }); + logger.info( + "No staged changes to commit - checking for unpushed commits" + ); } catch (_error) { hasUnstagedChanges = true; } @@ -279,4 +298,4 @@ export class GitHubWorkspaceManager { throw new Error(`Failed to commit and push changes: ${error}`); } } -} \ No newline at end of file +} diff --git a/modules/index.ts b/modules/index.ts index 69eff799..c8a36177 100644 --- a/modules/index.ts +++ b/modules/index.ts @@ -1,5 +1,11 @@ -import type { ModuleInterface, HomeTabModule, WorkerModule, OrchestratorModule, DispatcherModule } from './types'; -import { GitHubModule } from './github'; +import type { + ModuleInterface, + HomeTabModule, + WorkerModule, + OrchestratorModule, + DispatcherModule, +} from "./types"; +import { GitHubModule } from "./github"; export class ModuleRegistry { private modules: Map = new Map(); @@ -13,7 +19,7 @@ export class ModuleRegistry { async initAll(): Promise { // Auto-register available modules if not already registered this.autoRegisterModules(); - + for (const module of this.modules.values()) { if (module.init) { await module.init(); @@ -31,25 +37,25 @@ export class ModuleRegistry { getHomeTabModules(): HomeTabModule[] { return Array.from(this.modules.values()).filter( - (m): m is HomeTabModule => 'renderHomeTab' in m + (m): m is HomeTabModule => "renderHomeTab" in m ); } getWorkerModules(): WorkerModule[] { return Array.from(this.modules.values()).filter( - (m): m is WorkerModule => 'onSessionStart' in m || 'onSessionEnd' in m + (m): m is WorkerModule => "onSessionStart" in m || "onSessionEnd" in m ); } getOrchestratorModules(): OrchestratorModule[] { return Array.from(this.modules.values()).filter( - (m): m is OrchestratorModule => 'buildEnvVars' in m + (m): m is OrchestratorModule => "buildEnvVars" in m ); } getDispatcherModules(): DispatcherModule[] { return Array.from(this.modules.values()).filter( - (m): m is DispatcherModule => 'generateActionButtons' in m + (m): m is DispatcherModule => "generateActionButtons" in m ); } @@ -61,4 +67,4 @@ export class ModuleRegistry { // Global registry instance export const moduleRegistry = new ModuleRegistry(); -export * from './types'; \ No newline at end of file +export * from "./types"; diff --git a/modules/types.ts b/modules/types.ts index dc81217b..67ef6630 100644 --- a/modules/types.ts +++ b/modules/types.ts @@ -14,7 +14,11 @@ export interface HomeTabModule extends ModuleInterface { renderHomeTab?(userId: string): Promise; /** Handle home tab interactions */ - handleHomeTabAction?(actionId: string, userId: string, value?: any): Promise; + handleHomeTabAction?( + actionId: string, + userId: string, + value?: any + ): Promise; } export interface WorkerModule extends ModuleInterface { @@ -30,7 +34,10 @@ export interface WorkerModule extends ModuleInterface { export interface OrchestratorModule extends ModuleInterface { /** Build environment variables for worker container */ - buildEnvVars?(userId: string, baseEnv: Record): Promise>; + buildEnvVars?( + userId: string, + baseEnv: Record + ): Promise>; /** Get container address for module-specific services */ getContainerAddress?(): string; @@ -39,9 +46,13 @@ export interface OrchestratorModule extends ModuleInterface { export interface DispatcherModule extends ModuleInterface { /** Generate action buttons for thread responses */ generateActionButtons?(context: ThreadContext): Promise; - + /** Handle action button clicks */ - handleAction?(actionId: string, userId: string, context: any): Promise; + handleAction?( + actionId: string, + userId: string, + context: any + ): Promise; } export interface SessionContext { @@ -55,7 +66,7 @@ export interface SessionContext { export interface ActionButton { text: string; action_id: string; - style?: 'primary' | 'danger'; + style?: "primary" | "danger"; value?: string; } @@ -68,4 +79,4 @@ export interface ThreadContext { pullRequestUrl?: string; userMappings: Map; slackClient?: any; -} \ No newline at end of file +} diff --git a/packages/dispatcher/src/converters/github-actions.ts b/packages/dispatcher/src/converters/github-actions.ts index fa69db3d..451e6f5f 100644 --- a/packages/dispatcher/src/converters/github-actions.ts +++ b/packages/dispatcher/src/converters/github-actions.ts @@ -1,2 +1,2 @@ // This file has been moved to modules/github/actions.ts -// Please remove this file \ No newline at end of file +// Please remove this file diff --git a/packages/dispatcher/src/queue/slack-thread-processor.ts b/packages/dispatcher/src/queue/slack-thread-processor.ts index a676a913..347c28ae 100644 --- a/packages/dispatcher/src/queue/slack-thread-processor.ts +++ b/packages/dispatcher/src/queue/slack-thread-processor.ts @@ -36,7 +36,6 @@ export class ThreadResponseConsumer { private pgBoss: PgBoss; private slackClient: WebClient; private isRunning = false; - private repoManager?: any; private userMappings: Map; // slackUserId -> githubUsername private sessionBotMessages: Map = new Map(); // sessionKey -> botMessageTs @@ -48,10 +47,6 @@ export class ThreadResponseConsumer { this.pgBoss = new PgBoss(connectionString); this.slackClient = new WebClient(slackToken); this.userMappings = userMappings; - - // Get repository manager from GitHub module - const githubModule = moduleRegistry.getModule('github'); - this.repoManager = githubModule?.getRepositoryManager(); } /** @@ -395,7 +390,7 @@ export class ThreadResponseConsumer { } // Get action buttons from modules - let actionButtons: any[] = []; + const actionButtons: any[] = []; const dispatcherModules = moduleRegistry.getDispatcherModules(); for (const module of dispatcherModules) { if (module.generateActionButtons) { @@ -407,15 +402,17 @@ export class ThreadResponseConsumer { hasGitChanges: data.hasGitChanges, pullRequestUrl: data.pullRequestUrl, userMappings: this.userMappings, - slackClient: this.slackClient + slackClient: this.slackClient, }); - actionButtons.push(...moduleButtons.map(btn => ({ - type: "button", - text: { type: "plain_text", text: btn.text }, - action_id: btn.action_id, - style: btn.style, - value: btn.value - }))); + actionButtons.push( + ...moduleButtons.map((btn) => ({ + type: "button", + text: { type: "plain_text", text: btn.text }, + action_id: btn.action_id, + style: btn.style, + value: btn.value, + })) + ); } } @@ -629,7 +626,7 @@ export class ThreadResponseConsumer { }; // Get action buttons from modules - let actionButtons: any[] = []; + const actionButtons: any[] = []; const dispatcherModules = moduleRegistry.getDispatcherModules(); for (const module of dispatcherModules) { if (module.generateActionButtons) { @@ -641,15 +638,17 @@ export class ThreadResponseConsumer { hasGitChanges: data.hasGitChanges, pullRequestUrl: data.pullRequestUrl, userMappings: this.userMappings, - slackClient: this.slackClient + slackClient: this.slackClient, }); - actionButtons.push(...moduleButtons.map(btn => ({ - type: "button", - text: { type: "plain_text", text: btn.text }, - action_id: btn.action_id, - style: btn.style, - value: btn.value - }))); + actionButtons.push( + ...moduleButtons.map((btn) => ({ + type: "button", + text: { type: "plain_text", text: btn.text }, + action_id: btn.action_id, + style: btn.style, + value: btn.value, + })) + ); } } diff --git a/packages/dispatcher/src/simple-http.ts b/packages/dispatcher/src/simple-http.ts index 102d97de..35a1b909 100644 --- a/packages/dispatcher/src/simple-http.ts +++ b/packages/dispatcher/src/simple-http.ts @@ -8,9 +8,7 @@ import type { AnthropicProxy } from "./proxy/anthropic-proxy"; let healthServer: http.Server | null = null; let proxyApp: express.Application | null = null; -export function setupHealthEndpoints( - anthropicProxy?: AnthropicProxy -) { +export function setupHealthEndpoints(anthropicProxy?: AnthropicProxy) { if (healthServer) return; // Create Express app for proxy and health endpoints @@ -39,7 +37,6 @@ export function setupHealthEndpoints( logger.info("✅ Anthropic proxy enabled at :8080/api/anthropic"); } - // Create HTTP server with Express app healthServer = http.createServer(proxyApp); diff --git a/packages/dispatcher/src/slack/handlers/action-handler.ts b/packages/dispatcher/src/slack/handlers/action-handler.ts index a96bcf6b..d6715125 100644 --- a/packages/dispatcher/src/slack/handlers/action-handler.ts +++ b/packages/dispatcher/src/slack/handlers/action-handler.ts @@ -3,9 +3,10 @@ import { createLogger } from "@peerbot/shared"; const logger = createLogger("dispatcher"); import type { QueueProducer } from "../../queue/task-queue-producer"; -import type { DispatcherConfig, SlackContext } from "../../types"; +import type { SlackContext } from "../../types"; import type { MessageHandler } from "./message-handler"; import { moduleRegistry } from "../../../../../modules"; +import type { GitHubModule } from "../../../../../modules/github"; import { handleTryDemo } from "./demo-handler"; import { openRepositoryModal } from "./repository-modal-utils"; import { @@ -16,13 +17,9 @@ import { export class ActionHandler { constructor( - private repoManager: any, // Made generic since GitHub module is optional - _queueProducer: QueueProducer, // Not used directly in ActionHandler - private config: DispatcherConfig, + _queueProducer: QueueProducer, private messageHandler: MessageHandler - ) { - // queueProducer passed for consistency but not used directly - } + ) {} /** * Handle block action events @@ -42,11 +39,11 @@ export class ActionHandler { const dispatcherModules = moduleRegistry.getDispatcherModules(); for (const module of dispatcherModules) { if (module.handleAction) { - const moduleHandled = await module.handleAction(actionId, userId, { + const moduleHandled = await module.handleAction(actionId, userId, { channelId, client, body, - updateAppHome: this.updateAppHome.bind(this) + updateAppHome: this.updateAppHome.bind(this), }); if (moduleHandled) { handled = true; @@ -57,197 +54,205 @@ export class ActionHandler { if (!handled) { switch (actionId) { - - case "open_repository_modal": { - // Get GitHub functions from module - const gitHubModule = moduleRegistry.getModule('github'); - if (gitHubModule) { - const { getUserGitHubInfo } = await import('../../../../../modules/github/handlers'); - await openRepositoryModal({ - userId, - body, - client, - checkAdminStatus: false, - getGitHubUserInfo: getUserGitHubInfo, - }); + case "open_repository_modal": { + // Get GitHub functions from module + const gitHubModule = moduleRegistry.getModule("github"); + if (gitHubModule) { + const { getUserGitHubInfo } = await import( + "../../../../../modules/github/handlers" + ); + await openRepositoryModal({ + userId, + body, + client, + checkAdminStatus: false, + getGitHubUserInfo: getUserGitHubInfo, + }); + } + break; } - break; - } - case "open_github_login_modal": { - // Get GitHub auth URL from module - const gitHubModule = moduleRegistry.getModule('github'); - if (gitHubModule) { - const { generateGitHubAuthUrl } = await import('../../../../../modules/github/utils'); - const authUrl = generateGitHubAuthUrl(userId); - await client.views.open({ - trigger_id: body.trigger_id, - view: { - type: "modal", - callback_id: "github_login_modal", - title: { - type: "plain_text", - text: "Connect GitHub", - }, - blocks: [ - { - type: "header", - text: { + case "open_github_login_modal": { + // Get GitHub auth URL from module + const gitHubModule = moduleRegistry.getModule("github"); + if (gitHubModule) { + const { generateGitHubAuthUrl } = await import( + "../../../../../modules/github/utils" + ); + const authUrl = generateGitHubAuthUrl(userId); + await client.views.open({ + trigger_id: body.trigger_id, + view: { + type: "modal", + callback_id: "github_login_modal", + title: { type: "plain_text", - text: "🔗 Connect Your GitHub Account", - emoji: true, - }, - }, - { - type: "section", - text: { - type: "mrkdwn", - text: - "Connect your GitHub account to:\n\n" + - "• Access your repositories\n" + - "• Create new projects\n" + - "• Manage code with AI assistance\n\n" + - "*Your connection is secure and encrypted.*", - }, - }, - { - type: "divider", - }, - { - type: "section", - text: { - type: "mrkdwn", - text: "Click the button below to authenticate with GitHub:", + text: "Connect GitHub", }, - }, - { - type: "actions", - elements: [ + blocks: [ { - type: "button", + type: "header", text: { type: "plain_text", - text: "🚀 Connect with GitHub", + text: "🔗 Connect Your GitHub Account", emoji: true, }, - url: authUrl, - style: "primary", }, - ], - }, - { - type: "context", - elements: [ { - type: "mrkdwn", - text: "💡 *Note:* After connecting, you can select which repositories to work with.", + type: "section", + text: { + type: "mrkdwn", + text: + "Connect your GitHub account to:\n\n" + + "• Access your repositories\n" + + "• Create new projects\n" + + "• Manage code with AI assistance\n\n" + + "*Your connection is secure and encrypted.*", + }, + }, + { + type: "divider", + }, + { + type: "section", + text: { + type: "mrkdwn", + text: "Click the button below to authenticate with GitHub:", + }, + }, + { + type: "actions", + elements: [ + { + type: "button", + text: { + type: "plain_text", + text: "🚀 Connect with GitHub", + emoji: true, + }, + url: authUrl, + style: "primary", + }, + ], + }, + { + type: "context", + elements: [ + { + type: "mrkdwn", + text: "💡 *Note:* After connecting, you can select which repositories to work with.", + }, + ], }, ], + close: { + type: "plain_text", + text: "Cancel", + }, }, - ], - close: { - type: "plain_text", - text: "Cancel", - }, - }, - }); + }); + } + break; } - break; - } - case "github_connect": { - // This should be handled by the GitHub module, but fallback for compatibility - const gitHubModule = moduleRegistry.getModule('github'); - if (gitHubModule) { - const { handleGitHubConnect } = await import('../../../../../modules/github/handlers'); - await handleGitHubConnect(userId, channelId, client); + case "github_connect": { + // This should be handled by the GitHub module, but fallback for compatibility + const gitHubModule = moduleRegistry.getModule("github"); + if (gitHubModule) { + const { handleGitHubConnect } = await import( + "../../../../../modules/github/handlers" + ); + await handleGitHubConnect(userId, channelId, client); + } + break; } - break; - } - case "try_demo": { - // Check if this is from the home tab (view type will be 'home') - const fromHomeTab = body.view?.type === "home"; + case "try_demo": { + // Check if this is from the home tab (view type will be 'home') + const fromHomeTab = body.view?.type === "home"; - // Get the message timestamp to keep demo response in same thread (if not from home) - const demoMessageTs = body.message?.ts; + // Get the message timestamp to keep demo response in same thread (if not from home) + const demoMessageTs = body.message?.ts; - // Pass the fromHomeTab flag to ensure DM is sent when clicked from home - await handleTryDemo( - userId, - channelId, - client, - demoMessageTs, - fromHomeTab - ); - - // Clear cache and update home tab after demo setup - const username = await this.messageHandler.getOrCreateUserMapping( - userId, - client - ); - this.messageHandler.clearCacheForUser(username); - await this.updateAppHome(userId, client); - break; - } - - default: - // Handle blockkit form button clicks - if (actionId.startsWith("blockkit_form_")) { - await handleBlockkitForm( - actionId, - userId, - channelId, - messageTs, - body, - client - ); - } - // Handle executable code block buttons - else if ( - actionId.match(/^(bash|python|javascript|js|typescript|ts|sql|sh)_/) - ) { - await handleExecutableCodeBlock( - actionId, + // Pass the fromHomeTab flag to ensure DM is sent when clicked from home + await handleTryDemo( userId, channelId, - messageTs, - body, client, - (context: SlackContext, userRequest: string, client: any) => - this.messageHandler.handleUserRequest( - context, - userRequest, - client - ) + demoMessageTs, + fromHomeTab ); - } - // Handle stop worker button clicks - else if (actionId.startsWith("stop_worker_")) { - const deploymentName = actionId.replace("stop_worker_", ""); - await handleStopWorker( - deploymentName, - userId, - channelId, - messageTs, - client - ); - } - // Handle GitHub Pull Request button clicks - else if (actionId.startsWith("github_pr_")) { - await this.handleGitHubPullRequestAction( - actionId, + + // Clear cache and update home tab after demo setup + const username = await this.messageHandler.getOrCreateUserMapping( userId, - channelId, - messageTs, - body, client ); - } else { - logger.info( - `Unsupported action: ${actionId} from user ${userId} in channel ${channelId}` - ); + this.messageHandler.clearCacheForUser(username); + await this.updateAppHome(userId, client); + break; } + + default: + // Handle blockkit form button clicks + if (actionId.startsWith("blockkit_form_")) { + await handleBlockkitForm( + actionId, + userId, + channelId, + messageTs, + body, + client + ); + } + // Handle executable code block buttons + else if ( + actionId.match(/^(bash|python|javascript|js|typescript|ts|sql|sh)_/) + ) { + await handleExecutableCodeBlock( + actionId, + userId, + channelId, + messageTs, + body, + client, + (context: SlackContext, userRequest: string, client: any) => + this.messageHandler.handleUserRequest( + context, + userRequest, + client + ) + ); + } + // Handle stop worker button clicks + else if (actionId.startsWith("stop_worker_")) { + const deploymentName = actionId.replace("stop_worker_", ""); + await handleStopWorker( + deploymentName, + userId, + channelId, + messageTs, + client + ); + } + // Handle GitHub Pull Request button clicks + else if (actionId.startsWith("github_pr_")) { + await this.handleGitHubPullRequestAction( + actionId, + userId, + channelId, + messageTs, + body, + client + ); + } else { + logger.info( + `Unsupported action: ${actionId} from user ${userId} in channel ${channelId}` + ); + } + + break; + } } } @@ -354,13 +359,13 @@ export class ActionHandler { ); try { - const username = await this.messageHandler.getOrCreateUserMapping( - userId, - client - ); + await this.messageHandler.getOrCreateUserMapping(userId, client); // Get GitHub connection status for demo purposes - const githubUser = await getUserGitHubInfo(userId); + const gitHubModule = moduleRegistry.getModule("github"); + const githubUser = gitHubModule + ? await gitHubModule.getUserInfo(userId) + : { token: null, username: null }; const isGitHubConnected = !!githubUser.token; const blocks: any[] = [ @@ -383,7 +388,10 @@ export class ActionHandler { blocks.push({ type: "divider" }); } } catch (error) { - logger.error(`Failed to render home tab for module ${module.name}:`, error); + logger.error( + `Failed to render home tab for module ${module.name}:`, + error + ); } } @@ -425,7 +433,6 @@ export class ActionHandler { }, }); - // Update the app home view await client.views.publish({ user_id: userId, @@ -440,47 +447,4 @@ export class ActionHandler { logger.error(`Failed to update app home for user ${userId}:`, error); } } - - - /** - * Fetch repository README content - */ - private async fetchRepositoryReadme( - repositoryUrl: string - ): Promise { - try { - const urlParts = repositoryUrl - .replace(/^https?:\/\//, "") - .replace(/\.git$/, "") - .split("/"); - - if (urlParts.length < 3) { - return null; - } - - const owner = urlParts[1]; - const repo = urlParts[2]; - const branch = "main"; - - const readmeUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/README.md`; - - const response = await fetch(readmeUrl); - if (response.ok) { - const content = await response.text(); - return content.substring(0, 1000); - } - - // Try master branch - const masterUrl = `https://raw.githubusercontent.com/${owner}/${repo}/master/README.md`; - const masterResponse = await fetch(masterUrl); - if (masterResponse.ok) { - const content = await masterResponse.text(); - return content.substring(0, 1000); - } - } catch (error) { - logger.error(`Failed to fetch README for ${repositoryUrl}:`, error); - } - - return null; - } } diff --git a/packages/dispatcher/src/slack/handlers/repository-modal-utils.ts b/packages/dispatcher/src/slack/handlers/repository-modal-utils.ts index 766eb53c..6e6f1959 100644 --- a/packages/dispatcher/src/slack/handlers/repository-modal-utils.ts +++ b/packages/dispatcher/src/slack/handlers/repository-modal-utils.ts @@ -74,7 +74,9 @@ export async function openRepositoryModal({ }, }); - const { generateGitHubAuthUrl } = await import("../../../../../modules/github/utils"); + const { generateGitHubAuthUrl } = await import( + "../../../../../modules/github/utils" + ); const authUrl = generateGitHubAuthUrl(userId); blocks.push({ type: "section", diff --git a/packages/dispatcher/src/slack/handlers/shortcut-command-handler.ts b/packages/dispatcher/src/slack/handlers/shortcut-command-handler.ts index 2e8f8e4b..bb75d6e0 100644 --- a/packages/dispatcher/src/slack/handlers/shortcut-command-handler.ts +++ b/packages/dispatcher/src/slack/handlers/shortcut-command-handler.ts @@ -59,7 +59,9 @@ export class ShortcutCommandHandler { const userId = body.user.id; logger.info(`Create project shortcut triggered by ${userId}`); - const { getUserGitHubInfo } = await import("../../../../../modules/github/handlers"); + const { getUserGitHubInfo } = await import( + "../../../../../modules/github/handlers" + ); await openRepositoryModal({ userId, body, @@ -145,7 +147,9 @@ export class ShortcutCommandHandler { threadTs?: string ): Promise { // Check if user has GitHub connected - const { getUserGitHubInfo } = await import("../../../../../modules/github/handlers"); + const { getUserGitHubInfo } = await import( + "../../../../../modules/github/handlers" + ); const githubUser = await getUserGitHubInfo(userId); const isGitHubConnected = !!githubUser.token; @@ -437,8 +441,10 @@ export class ShortcutCommandHandler { // Create new repository // Get GitHub user info // const username = await this.messageHandler.getOrCreateUserMapping(userId, client); // Currently unused - const { getUserGitHubInfo } = await import("../../../../../modules/github/handlers"); - const githubUser = await getUserGitHubInfo(userId); + const { getUserGitHubInfo } = await import( + "../../../../../modules/github/handlers" + ); + const githubUser = await getUserGitHubInfo(userId); if (!githubUser.token) { throw new Error( diff --git a/packages/dispatcher/src/slack/slack-event-handlers.ts b/packages/dispatcher/src/slack/slack-event-handlers.ts index fddc566a..ba1dc014 100644 --- a/packages/dispatcher/src/slack/slack-event-handlers.ts +++ b/packages/dispatcher/src/slack/slack-event-handlers.ts @@ -17,6 +17,7 @@ import { MessageHandler } from "./handlers/message-handler"; import { ActionHandler } from "./handlers/action-handler"; import { ShortcutCommandHandler } from "./handlers/shortcut-command-handler"; import { moduleRegistry } from "../../../../modules"; +import type { GitHubModule } from "../../../../modules/github"; /** * Queue-based Slack event handlers that route messages to appropriate queues @@ -33,11 +34,11 @@ export class SlackEventHandlers { private config: DispatcherConfig ) { // Get repository manager from GitHub module (optional) - const githubModule = moduleRegistry.getModule('github'); + const githubModule = moduleRegistry.getModule("github"); const repoManager = githubModule?.getRepositoryManager(); - + if (!repoManager) { - logger.warn('GitHub module not available - some features may be limited'); + logger.warn("GitHub module not available - some features may be limited"); } // Initialize specialized handlers @@ -46,12 +47,7 @@ export class SlackEventHandlers { repoManager, config ); - this.actionHandler = new ActionHandler( - repoManager, - queueProducer, - config, - this.messageHandler - ); + this.actionHandler = new ActionHandler(queueProducer, this.messageHandler); this.shortcutCommandHandler = new ShortcutCommandHandler( app, config, @@ -80,6 +76,11 @@ export class SlackEventHandlers { const query = options?.value || ""; const userId = body.user?.id; + if (!userId) { + await ack({ options: [] }); + return; + } + logger.info( `Repository search triggered - query: "${query}", user: ${userId}` ); @@ -87,7 +88,14 @@ export class SlackEventHandlers { try { // Get user's GitHub token logger.info(`Fetching GitHub info for user ${userId}`); - const githubUser = await getUserGitHubInfo(userId); + const gitHubModule = moduleRegistry.getModule("github"); + if (!gitHubModule) { + logger.warn("GitHub module not available - returning empty options"); + await ack({ options: [] }); + return; + } + + const githubUser = await gitHubModule.getUserInfo(userId); logger.info( `GitHub user info retrieved: token=${!!githubUser.token}, username=${githubUser.username}` ); diff --git a/packages/dispatcher/src/types.ts b/packages/dispatcher/src/types.ts index a568a50a..29dd8610 100644 --- a/packages/dispatcher/src/types.ts +++ b/packages/dispatcher/src/types.ts @@ -19,7 +19,6 @@ export interface SlackConfig { allowPrivateChannels?: boolean; } - export interface QueueConfig { directMessage: string; messageQueue: string; @@ -36,7 +35,6 @@ export interface AnthropicProxyConfig { anthropicBaseUrl?: string; } - export interface DispatcherConfig { slack: SlackConfig; claude: Partial; diff --git a/packages/orchestrator/src/base/BaseDeploymentManager.ts b/packages/orchestrator/src/base/BaseDeploymentManager.ts index c227aa0d..0326a03b 100644 --- a/packages/orchestrator/src/base/BaseDeploymentManager.ts +++ b/packages/orchestrator/src/base/BaseDeploymentManager.ts @@ -226,7 +226,7 @@ export abstract class BaseDeploymentManager { const dbHost = dbUrl.hostname; const dbPort = dbUrl.port || "5432"; // Default PostgreSQL port - const envVars: { [key: string]: string } = { + let envVars: { [key: string]: string } = { USER_ID: userId, USERNAME: username, DEPLOYMENT_NAME: deploymentName, @@ -258,12 +258,12 @@ export abstract class BaseDeploymentManager { envVars.GITHUB_TOKEN = process.env.GITHUB_TOKEN; } // OAuth token is now always handled by the proxy in dispatcher - + // Add module-specific environment variables try { - envVars = await buildModuleEnvVars(messageData?.userId || '', envVars); + envVars = await buildModuleEnvVars(messageData?.userId || "", envVars); } catch (error) { - logger.warn('Failed to build module environment variables:', error); + logger.warn("Failed to build module environment variables:", error); } } diff --git a/packages/orchestrator/src/index.ts b/packages/orchestrator/src/index.ts index 7b048772..e1d75ad7 100644 --- a/packages/orchestrator/src/index.ts +++ b/packages/orchestrator/src/index.ts @@ -30,7 +30,7 @@ class PeerbotOrchestrator { constructor(config: OrchestratorConfig) { this.config = config; - + // Register modules moduleRegistry.register(new GitHubModule()); this.dbPool = new DatabasePool(config.database); @@ -187,7 +187,7 @@ class PeerbotOrchestrator { // Initialize modules await moduleRegistry.initAll(); logger.info("✅ Modules initialized"); - + // Run database migrations using dbmate (this will create database and run migrations) await this.runDbmateMigrations(); diff --git a/packages/orchestrator/src/module-integration.ts b/packages/orchestrator/src/module-integration.ts index 87a7a616..f2c5e5cf 100644 --- a/packages/orchestrator/src/module-integration.ts +++ b/packages/orchestrator/src/module-integration.ts @@ -1,18 +1,24 @@ -import { moduleRegistry } from '../../../modules'; +import { moduleRegistry } from "../../../modules"; -export async function buildModuleEnvVars(userId: string, baseEnv: Record): Promise> { +export async function buildModuleEnvVars( + userId: string, + baseEnv: Record +): Promise> { let envVars = { ...baseEnv }; - + const orchestratorModules = moduleRegistry.getOrchestratorModules(); for (const module of orchestratorModules) { if (module.buildEnvVars) { try { envVars = await module.buildEnvVars(userId, envVars); } catch (error) { - console.error(`Failed to build env vars for module ${module.name}:`, error); + console.error( + `Failed to build env vars for module ${module.name}:`, + error + ); } } } - + return envVars; -} \ No newline at end of file +} diff --git a/packages/shared/src/config/index.ts b/packages/shared/src/config/index.ts index f73d60af..bc972a92 100644 --- a/packages/shared/src/config/index.ts +++ b/packages/shared/src/config/index.ts @@ -24,7 +24,6 @@ export const SlackConfigSchema = z.object({ .default("INFO"), }); - // Claude configuration schema export const ClaudeConfigSchema = z.object({ apiKey: z.string().optional(), @@ -112,7 +111,6 @@ export function loadSlackConfig(): SlackConfig { return SlackConfigSchema.parse(config); } - /** * Loads Claude configuration from environment variables */ diff --git a/packages/shared/src/errors/dispatcher-errors.ts b/packages/shared/src/errors/dispatcher-errors.ts index 2c84d63c..7c986159 100644 --- a/packages/shared/src/errors/dispatcher-errors.ts +++ b/packages/shared/src/errors/dispatcher-errors.ts @@ -1,2 +1,2 @@ // GitHub-specific errors moved to modules/github/errors.ts -// This file can be removed \ No newline at end of file +// This file can be removed diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index 1d39f890..0396bef5 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -28,7 +28,7 @@ async function main() { // Initialize available modules await moduleRegistry.initAll(); logger.info("✅ Modules initialized"); - + logger.info( "🔄 Starting in queue mode (dynamic deployment-based persistent worker)" ); diff --git a/packages/worker/src/module-integration.ts b/packages/worker/src/module-integration.ts index 59dd21e4..3208fac4 100644 --- a/packages/worker/src/module-integration.ts +++ b/packages/worker/src/module-integration.ts @@ -1,25 +1,36 @@ -import { moduleRegistry, type SessionContext, type ActionButton } from '../../../modules'; +import { + moduleRegistry, + type SessionContext, + type ActionButton, +} from "../../../modules"; -export async function onSessionStart(context: SessionContext): Promise { +export async function onSessionStart( + context: SessionContext +): Promise { let updatedContext = context; - + const workerModules = moduleRegistry.getWorkerModules(); for (const module of workerModules) { if (module.onSessionStart) { try { updatedContext = await module.onSessionStart(updatedContext); } catch (error) { - console.error(`Failed to execute onSessionStart for module ${module.name}:`, error); + console.error( + `Failed to execute onSessionStart for module ${module.name}:`, + error + ); } } } - + return updatedContext; } -export async function onSessionEnd(context: SessionContext): Promise { +export async function onSessionEnd( + context: SessionContext +): Promise { const allButtons: ActionButton[] = []; - + const workerModules = moduleRegistry.getWorkerModules(); for (const module of workerModules) { if (module.onSessionEnd) { @@ -27,11 +38,14 @@ export async function onSessionEnd(context: SessionContext): Promise { try { await module.initWorkspace(config); } catch (error) { - console.error(`Failed to initialize workspace for module ${module.name}:`, error); + console.error( + `Failed to initialize workspace for module ${module.name}:`, + error + ); } } } -} \ No newline at end of file +} diff --git a/packages/worker/src/task-queue-integration.ts b/packages/worker/src/task-queue-integration.ts index 6f986e74..96e42356 100644 --- a/packages/worker/src/task-queue-integration.ts +++ b/packages/worker/src/task-queue-integration.ts @@ -2,6 +2,7 @@ import PgBoss from "pg-boss"; import { createLogger } from "@peerbot/shared"; +import type { GitHubModule } from "../../../modules/github"; const logger = createLogger("worker"); @@ -280,11 +281,16 @@ export class QueueIntegration { // Check if GitHub CLI is authenticated through module let isAuthenticated = false; try { - const { moduleRegistry } = await import('../../../modules'); - const githubModule = moduleRegistry.getModule('github'); - if (githubModule && 'isGitHubCLIAuthenticated' in githubModule) { - isAuthenticated = await (githubModule as any).isGitHubCLIAuthenticated(workingDir); - logger.info(`GitHub CLI authentication status: ${isAuthenticated}`); + const { moduleRegistry } = await import("../../../modules"); + const githubModule = + moduleRegistry.getModule("github"); + if (githubModule && "isGitHubCLIAuthenticated" in githubModule) { + isAuthenticated = await ( + githubModule as any + ).isGitHubCLIAuthenticated(workingDir); + logger.info( + `GitHub CLI authentication status: ${isAuthenticated}` + ); } else { // Fallback to direct check logger.info("Checking GitHub CLI authentication (fallback)..."); @@ -598,13 +604,18 @@ export class QueueIntegration { // Generate GitHub OAuth URL for authentication through module let authUrl = `${process.env.INGRESS_URL || "http://localhost:8080"}/login`; try { - const { moduleRegistry } = await import('../../../modules'); - const githubModule = moduleRegistry.getModule('github'); - if (githubModule && 'generateOAuthUrl' in githubModule) { - authUrl = (githubModule as any).generateOAuthUrl(process.env.USER_ID || ''); + const { moduleRegistry } = await import("../../../modules"); + const githubModule = moduleRegistry.getModule("github"); + if (githubModule && "generateOAuthUrl" in githubModule) { + authUrl = (githubModule as any).generateOAuthUrl( + process.env.USER_ID || "" + ); } } catch (moduleError) { - console.warn('Failed to get GitHub OAuth URL from module, using fallback:', moduleError); + console.warn( + "Failed to get GitHub OAuth URL from module, using fallback:", + moduleError + ); } // Create a rich message with buttons diff --git a/packages/worker/src/workspace-manager.ts b/packages/worker/src/workspace-manager.ts index 14c838c2..5b59f253 100644 --- a/packages/worker/src/workspace-manager.ts +++ b/packages/worker/src/workspace-manager.ts @@ -5,6 +5,7 @@ import { mkdir, stat } from "node:fs/promises"; import { join } from "node:path"; import { promisify } from "node:util"; import { createLogger } from "@peerbot/shared"; +import type { GitHubModule } from "../../../modules/github"; import type { GitRepository, WorkspaceInfo, @@ -117,16 +118,19 @@ export class WorkspaceManager { await this.setupGitConfig(userDirectory, username); // Setup GitHub CLI authentication through module if available - if (process.env.GITHUB_TOKEN && repositoryUrl.includes('github.com')) { + if (process.env.GITHUB_TOKEN && repositoryUrl.includes("github.com")) { try { - const { moduleRegistry } = await import('../../../modules'); - const githubModule = moduleRegistry.getModule('github'); - if (githubModule && 'init' in githubModule) { + const { moduleRegistry } = await import("../../../modules"); + const githubModule = moduleRegistry.getModule("github"); + if (githubModule && "init" in githubModule) { // GitHub module will handle CLI authentication during its own setup logger.info("GitHub module will handle CLI authentication"); } } catch (error) { - logger.warn("Failed to setup GitHub CLI authentication through module:", error); + logger.warn( + "Failed to setup GitHub CLI authentication through module:", + error + ); // Non-fatal - continue without gh CLI } } @@ -180,11 +184,14 @@ export class WorkspaceManager { // Use GitHub token for authentication through module let authenticatedUrl = repositoryUrl; - if (this.config.githubToken && repositoryUrl.includes('github.com')) { - const { moduleRegistry } = await import('../../../modules'); - const githubModule = moduleRegistry.getModule('github'); - if (githubModule && 'addGitHubAuth' in githubModule) { - authenticatedUrl = (githubModule as any).addGitHubAuth(repositoryUrl, this.config.githubToken); + if (this.config.githubToken && repositoryUrl.includes("github.com")) { + const { moduleRegistry } = await import("../../../modules"); + const githubModule = moduleRegistry.getModule("github"); + if (githubModule && "addGitHubAuth" in githubModule) { + authenticatedUrl = (githubModule as any).addGitHubAuth( + repositoryUrl, + this.config.githubToken + ); } } @@ -393,7 +400,6 @@ export class WorkspaceManager { } } - /** * Check if directory exists */ diff --git a/tsconfig.json b/tsconfig.json index 090fe17e..20f7d697 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,9 +23,23 @@ // Some stricter flags "noUnusedLocals": true, "noUnusedParameters": true, - "noPropertyAccessFromIndexSignature": false + "noPropertyAccessFromIndexSignature": false, + + // Workspace module resolution + "baseUrl": ".", + "paths": { + "@peerbot/shared": ["packages/shared/src/index.ts"], + "@peerbot/shared/*": ["packages/shared/src/*"], + "@peerbot/dispatcher": ["packages/dispatcher/src/index.ts"], + "@peerbot/dispatcher/*": ["packages/dispatcher/src/*"], + "@peerbot/orchestrator": ["packages/orchestrator/src/index.ts"], + "@peerbot/orchestrator/*": ["packages/orchestrator/src/*"], + "@peerbot/worker": ["packages/worker/src/index.ts"], + "@peerbot/worker/*": ["packages/worker/src/*"] + } }, "include": [ + "modules/**/*", "packages/*/src/**/*", "packages/*/__tests__/**/*", "src/**/*",