diff --git a/packages/cli/src/commands/doctor.ts b/packages/cli/src/commands/doctor.ts index d0e7fcc07..5bdaa0dd9 100644 --- a/packages/cli/src/commands/doctor.ts +++ b/packages/cli/src/commands/doctor.ts @@ -343,7 +343,9 @@ async function sendTestNotifications( const targets = new Map(); for (const [name, notifierConfig] of configuredNotifiers) { - targets.set(notifierConfig.plugin, { label: name, pluginName: notifierConfig.plugin }); + if (notifierConfig.plugin) { + targets.set(notifierConfig.plugin, { label: name, pluginName: notifierConfig.plugin }); + } } for (const name of activeNotifierNames) { diff --git a/packages/cli/src/commands/status.ts b/packages/cli/src/commands/status.ts index 625e06370..0e17d10a1 100644 --- a/packages/cli/src/commands/status.ts +++ b/packages/cli/src/commands/status.ts @@ -386,7 +386,7 @@ export function registerStatus(program: Command): void { let unverifiedTotal = 0; for (const projectId of projectIds) { const project: ProjectConfig | undefined = config.projects[projectId]; - if (!project?.tracker) continue; + if (!project?.tracker?.plugin) continue; const tracker = registry.get("tracker", project.tracker.plugin); if (!tracker?.listIssues) continue; try { diff --git a/packages/cli/src/commands/verify.ts b/packages/cli/src/commands/verify.ts index 40d6ee043..c82223a87 100644 --- a/packages/cli/src/commands/verify.ts +++ b/packages/cli/src/commands/verify.ts @@ -60,6 +60,10 @@ async function getTracker( const registry = createPluginRegistry(); await registry.loadFromConfig(config, importPluginModuleFromSource); + if (!project.tracker.plugin) { + console.error(chalk.red("Project tracker plugin not configured.")); + process.exit(1); + } const tracker = registry.get("tracker", project.tracker.plugin); if (!tracker) { console.error(chalk.red(`Tracker plugin "${project.tracker.plugin}" not found.`)); diff --git a/packages/web/src/app/api/issues/route.ts b/packages/web/src/app/api/issues/route.ts index 892d3f6c8..3212afd34 100644 --- a/packages/web/src/app/api/issues/route.ts +++ b/packages/web/src/app/api/issues/route.ts @@ -21,7 +21,7 @@ export async function GET(request: NextRequest) { for (const [projectId, project] of Object.entries(config.projects)) { if (projectFilter && projectId !== projectFilter) continue; - if (!project.tracker) continue; + if (!project.tracker?.plugin) continue; const tracker = registry.get("tracker", project.tracker.plugin); if (!tracker?.listIssues) continue; @@ -76,7 +76,7 @@ export async function POST(request: NextRequest) { } const project = config.projects[projectId]; - if (!project.tracker) { + if (!project.tracker?.plugin) { return NextResponse.json({ error: "No tracker configured for this project" }, { status: 422 }); } diff --git a/packages/web/src/app/api/verify/route.ts b/packages/web/src/app/api/verify/route.ts index f0c00e847..44c0ef627 100644 --- a/packages/web/src/app/api/verify/route.ts +++ b/packages/web/src/app/api/verify/route.ts @@ -64,7 +64,7 @@ export async function POST(req: NextRequest) { return NextResponse.json({ error: projectErr }, { status: 404 }); } const project = config.projects[projectId]; - if (!project.tracker) { + if (!project.tracker?.plugin) { return NextResponse.json({ error: `Project ${projectId} has no tracker` }, { status: 422 }); } diff --git a/packages/web/src/lib/scm-webhooks.ts b/packages/web/src/lib/scm-webhooks.ts index 105dca848..06534e4e9 100644 --- a/packages/web/src/lib/scm-webhooks.ts +++ b/packages/web/src/lib/scm-webhooks.ts @@ -34,7 +34,7 @@ export function findWebhookProjects( pathname: string, ): WebhookProjectMatch[] { return Object.entries(config.projects).flatMap(([projectId, project]) => { - if (!project.scm) return []; + if (!project.scm?.plugin) return []; const webhookPath = getProjectWebhookPath(project); if (!webhookPath || webhookPath !== pathname) return []; const scm = registry.get("scm", project.scm.plugin); diff --git a/packages/web/src/lib/serialize.ts b/packages/web/src/lib/serialize.ts index d8668cb49..6cce47e10 100644 --- a/packages/web/src/lib/serialize.ts +++ b/packages/web/src/lib/serialize.ts @@ -364,7 +364,7 @@ export async function enrichSessionsMetadata( // Enrich issue labels (synchronous — must run before async title enrichment) projects.forEach((project, i) => { - if (!dashboardSessions[i].issueUrl || !project?.tracker) return; + if (!dashboardSessions[i].issueUrl || !project?.tracker?.plugin) return; const tracker = registry.get("tracker", project.tracker.plugin); if (!tracker) return; enrichSessionIssue(dashboardSessions[i], tracker, project); @@ -385,7 +385,7 @@ export async function enrichSessionsMetadata( if (!dashboardSessions[i].issueUrl || !dashboardSessions[i].issueLabel) { return Promise.resolve(); } - if (!project?.tracker) return Promise.resolve(); + if (!project?.tracker?.plugin) return Promise.resolve(); const tracker = registry.get("tracker", project.tracker.plugin); if (!tracker) return Promise.resolve(); return enrichSessionIssueTitle(dashboardSessions[i], tracker, project); diff --git a/packages/web/src/lib/services.ts b/packages/web/src/lib/services.ts index e815bf69f..e6a274b92 100644 --- a/packages/web/src/lib/services.ts +++ b/packages/web/src/lib/services.ts @@ -137,7 +137,7 @@ async function labelIssuesForVerification( for (const session of mergedSessions) { const key = `${session.projectId}:${session.issueId}`; const project = config.projects[session.projectId]; - if (!project?.tracker) { + if (!project?.tracker?.plugin) { processedIssues.add(key); continue; } @@ -180,7 +180,7 @@ async function relabelReopenedIssues( registry: PluginRegistry, ): Promise { for (const [, project] of Object.entries(config.projects)) { - if (!project.tracker) continue; + if (!project.tracker?.plugin) continue; const tracker = registry.get("tracker", project.tracker.plugin); if (!tracker?.listIssues || !tracker.updateIssue) continue; @@ -240,7 +240,7 @@ export async function pollBacklog(): Promise { for (const [projectId, project] of Object.entries(config.projects)) { if (availableSlots <= 0) break; - if (!project.tracker) continue; + if (!project.tracker?.plugin) continue; const tracker = registry.get("tracker", project.tracker.plugin); if (!tracker?.listIssues) continue; @@ -352,7 +352,7 @@ export async function getBacklogIssues(): Promise("tracker", project.tracker.plugin); if (!tracker?.listIssues) continue; @@ -380,7 +380,7 @@ export async function getVerifyIssues(): Promise("tracker", project.tracker.plugin); if (!tracker?.listIssues) continue; @@ -404,6 +404,6 @@ export async function getVerifyIssues(): Promise("scm", project.scm.plugin); }