fix: persist issue tracker provider type in projects.json (#193) (#194)

Problem: Provider type (github/gitlab) was auto-detected on every
createProvider() call but never persisted, causing loss of
configuration after session restart.

Solution:
- Add 'provider' field to Project type
- Store detected provider type during project registration
- Pass stored provider type to createProvider() calls

Changes:
- lib/projects.ts: Add provider field to Project type
- lib/tools/project-register.ts: Save providerType to projects.json
- lib/tool-helpers.ts: Pass project.provider to createProvider
- lib/services/*.ts: Pass project.provider to createProvider

Impact: Issue tracker source now persists across restarts. Existing
projects will auto-detect on next use and should be re-registered or
manually edited to add provider field.

Fixes #193
This commit is contained in:
Lauren ten Hoor
2026-02-14 18:36:40 +08:00
committed by GitHub
parent c22c25bbe8
commit 01ad5d326c
6 changed files with 8 additions and 4 deletions

View File

@@ -22,6 +22,8 @@ export type Project = {
deployBranch: string; deployBranch: string;
/** Messaging channel for this project's group (e.g. "telegram", "whatsapp", "discord", "slack"). Stored at registration time. */ /** Messaging channel for this project's group (e.g. "telegram", "whatsapp", "discord", "slack"). Stored at registration time. */
channel?: string; channel?: string;
/** Issue tracker provider type (github or gitlab). Auto-detected at registration, stored for reuse. */
provider?: "github" | "gitlab";
/** Project-level role execution: parallel (DEV+QA can run simultaneously) or sequential (only one role at a time). Default: parallel */ /** Project-level role execution: parallel (DEV+QA can run simultaneously) or sequential (only one role at a time). Default: parallel */
roleExecution?: "parallel" | "sequential"; roleExecution?: "parallel" | "sequential";
maxDevWorkers?: number; maxDevWorkers?: number;

View File

@@ -304,7 +304,7 @@ async function performHealthPass(
project: any, project: any,
sessions: SessionLookup | null, sessions: SessionLookup | null,
): Promise<number> { ): Promise<number> {
const { provider } = await createProvider({ repo: project.repo }); const { provider } = await createProvider({ repo: project.repo, provider: project.provider });
let fixedCount = 0; let fixedCount = 0;
for (const role of getAllRoleIds()) { for (const role of getAllRoleIds()) {

View File

@@ -110,7 +110,7 @@ export async function fetchProjectQueues(
project: Project, project: Project,
workflow: WorkflowConfig = DEFAULT_WORKFLOW, workflow: WorkflowConfig = DEFAULT_WORKFLOW,
): Promise<Record<string, Issue[]>> { ): Promise<Record<string, Issue[]>> {
const { provider } = await createProvider({ repo: project.repo }); const { provider } = await createProvider({ repo: project.repo, provider: project.provider });
const queueLabels = getQueueLabelsWithPriority(workflow); const queueLabels = getQueueLabelsWithPriority(workflow);
const queues: Record<string, Issue[]> = {}; const queues: Record<string, Issue[]> = {};

View File

@@ -162,7 +162,7 @@ export async function projectTick(opts: {
const project = (await readProjects(workspaceDir)).projects[groupId]; const project = (await readProjects(workspaceDir)).projects[groupId];
if (!project) return { pickups: [], skipped: [{ reason: `Project not found: ${groupId}` }] }; if (!project) return { pickups: [], skipped: [{ reason: `Project not found: ${groupId}` }] };
const provider = opts.provider ?? (await createProvider({ repo: project.repo })).provider; const provider = opts.provider ?? (await createProvider({ repo: project.repo, provider: project.provider })).provider;
const roleExecution = project.roleExecution ?? "parallel"; const roleExecution = project.roleExecution ?? "parallel";
const roles: Role[] = targetRole ? [targetRole] : getAllRoleIds() as Role[]; const roles: Role[] = targetRole ? [targetRole] : getAllRoleIds() as Role[];

View File

@@ -36,9 +36,10 @@ export async function resolveProject(
/** /**
* Create an issue provider for a project. * Create an issue provider for a project.
* Uses stored provider type from project config if available, otherwise auto-detects.
*/ */
export async function resolveProvider(project: Project): Promise<ProviderWithType> { export async function resolveProvider(project: Project): Promise<ProviderWithType> {
return createProvider({ repo: project.repo }); return createProvider({ repo: project.repo, provider: project.provider });
} }
/** /**

View File

@@ -161,6 +161,7 @@ export function createProjectRegisterTool() {
baseBranch, baseBranch,
deployBranch, deployBranch,
channel, channel,
provider: providerType,
roleExecution, roleExecution,
dev: emptyWorkerState([...getLevelsForRole("dev")]), dev: emptyWorkerState([...getLevelsForRole("dev")]),
qa: emptyWorkerState([...getLevelsForRole("qa")]), qa: emptyWorkerState([...getLevelsForRole("qa")]),