refactor: remove glabPath and ghPath options from providers and update related code

This commit is contained in:
Lauren ten Hoor
2026-02-09 22:33:46 +08:00
parent 7a29da4c83
commit 3a2e739a62
12 changed files with 40 additions and 75 deletions

View File

@@ -29,14 +29,6 @@ const plugin = {
qa: { type: "string", description: "QA engineer model" },
},
},
glabPath: {
type: "string",
description: "Path to glab CLI binary. Defaults to 'glab' on PATH.",
},
ghPath: {
type: "string",
description: "Path to gh CLI binary. Defaults to 'gh' on PATH.",
},
},
},

View File

@@ -25,7 +25,6 @@ const STATE_LABELS = [
export type StateLabel = (typeof STATE_LABELS)[number];
type GlabOptions = {
glabPath?: string;
repoPath: string;
};
@@ -33,8 +32,7 @@ async function glab(
args: string[],
opts: GlabOptions,
): Promise<string> {
const bin = opts.glabPath ?? "glab";
const { stdout } = await execFileAsync(bin, args, {
const { stdout } = await execFileAsync("glab", args, {
cwd: opts.repoPath,
timeout: 30_000,
});

View File

@@ -24,7 +24,6 @@ import {
const execFileAsync = promisify(execFile);
export type GitHubProviderOptions = {
ghPath?: string;
repoPath: string;
};
@@ -50,16 +49,14 @@ function toIssue(gh: GhIssue): Issue {
}
export class GitHubProvider implements IssueProvider {
private ghPath: string;
private repoPath: string;
constructor(opts: GitHubProviderOptions) {
this.ghPath = opts.ghPath ?? "gh";
this.repoPath = opts.repoPath;
}
private async gh(args: string[]): Promise<string> {
const { stdout } = await execFileAsync(this.ghPath, args, {
const { stdout } = await execFileAsync("gh", args, {
cwd: this.repoPath,
timeout: 30_000,
});

View File

@@ -20,21 +20,18 @@ import {
const execFileAsync = promisify(execFile);
export type GitLabProviderOptions = {
glabPath?: string;
repoPath: string;
};
export class GitLabProvider implements IssueProvider {
private glabPath: string;
private repoPath: string;
constructor(opts: GitLabProviderOptions) {
this.glabPath = opts.glabPath ?? "glab";
this.repoPath = opts.repoPath;
}
private async glab(args: string[]): Promise<string> {
const { stdout } = await execFileAsync(this.glabPath, args, {
const { stdout } = await execFileAsync("glab", args, {
cwd: this.repoPath,
timeout: 30_000,
});
@@ -76,7 +73,7 @@ export class GitLabProvider implements IssueProvider {
const { promisify } = await import("node:util");
const execAsync = promisify(exec);
let cmd = `${this.glabPath} issue create --title "${title.replace(/"/g, '\\"')}" --description "$(cat ${tempFile})" --label "${label}" --output json`;
let cmd = `glab issue create --title "${title.replace(/"/g, '\\"')}" --description "$(cat ${tempFile})" --label "${label}" --output json`;
if (assignees && assignees.length > 0) {
cmd += ` --assignee "${assignees.join(",")}"`;
}

View File

@@ -11,12 +11,12 @@ import { execFileSync } from "node:child_process";
import type { IssueProvider } from "../issue-provider.js";
import { GitLabProvider } from "./gitlab.js";
import { GitHubProvider } from "./github.js";
import { resolveRepoPath } from "../utils.js";
export type ProviderOptions = {
provider?: "gitlab" | "github";
glabPath?: string;
ghPath?: string;
repoPath: string;
repo?: string;
repoPath?: string;
};
function detectProvider(repoPath: string): "gitlab" | "github" {
@@ -39,16 +39,21 @@ export type ProviderWithType = {
};
export function createProvider(opts: ProviderOptions): ProviderWithType {
const type = opts.provider ?? detectProvider(opts.repoPath);
const repoPath = opts.repoPath ?? (opts.repo ? resolveRepoPath(opts.repo) : null);
if (!repoPath) {
throw new Error("Either repoPath or repo must be provided to createProvider");
}
const type = opts.provider ?? detectProvider(repoPath);
if (type === "github") {
return {
provider: new GitHubProvider({ ghPath: opts.ghPath, repoPath: opts.repoPath }),
provider: new GitHubProvider({ repoPath }),
type: "github",
};
}
return {
provider: new GitLabProvider({ glabPath: opts.glabPath, repoPath: opts.repoPath }),
provider: new GitLabProvider({ repoPath }),
type: "gitlab",
};
}

View File

@@ -170,9 +170,7 @@ export function createProjectRegisterTool(api: OpenClawPluginApi) {
const repoPath = resolveRepoPath(repo);
// 3. Create provider and verify it works
const glabPath = (api.pluginConfig as Record<string, unknown>)?.glabPath as string | undefined;
const ghPath = (api.pluginConfig as Record<string, unknown>)?.ghPath as string | undefined;
const { provider, type: providerType } = createProvider({ glabPath, ghPath, repoPath });
const { provider, type: providerType } = createProvider({ repo });
const healthy = await provider.healthCheck();
if (!healthy) {

View File

@@ -11,7 +11,6 @@ import { type StateLabel } from "../issue-provider.js";
import { createProvider } from "../providers/index.js";
import { log as auditLog } from "../audit.js";
import { detectContext, generateGuardrails } from "../context-guard.js";
import { resolveRepoPath } from "../utils.js";
export function createQueueStatusTool(api: OpenClawPluginApi) {
return (ctx: ToolContext) => ({
@@ -69,11 +68,8 @@ export function createQueueStatusTool(api: OpenClawPluginApi) {
const project = getProject(data, pid);
if (!project) continue;
const repoPath = resolveRepoPath(project.repo);
const { provider } = createProvider({
glabPath: (api.pluginConfig as Record<string, unknown>)?.glabPath as string | undefined,
ghPath: (api.pluginConfig as Record<string, unknown>)?.ghPath as string | undefined,
repoPath,
repo: project.repo,
});
// Fetch queue counts from issue tracker

View File

@@ -11,7 +11,6 @@ import { readProjects, updateWorker, getSessionForModel } from "../projects.js";
import { type StateLabel } from "../issue-provider.js";
import { createProvider } from "../providers/index.js";
import { log as auditLog } from "../audit.js";
import { resolveRepoPath } from "../utils.js";
export function createSessionHealthTool(api: OpenClawPluginApi) {
return (ctx: ToolContext) => ({
@@ -48,11 +47,8 @@ export function createSessionHealthTool(api: OpenClawPluginApi) {
let fixesApplied = 0;
for (const [groupId, project] of Object.entries(data.projects)) {
const repoPath = resolveRepoPath(project.repo);
const { provider } = createProvider({
glabPath: (api.pluginConfig as Record<string, unknown>)?.glabPath as string | undefined,
ghPath: (api.pluginConfig as Record<string, unknown>)?.ghPath as string | undefined,
repoPath,
repo: project.repo,
});
for (const role of ["dev", "qa"] as const) {

View File

@@ -16,6 +16,7 @@ import { log as auditLog } from "../audit.js";
import { dispatchTask } from "../dispatch.js";
import { type StateLabel } from "../issue-provider.js";
import { createProvider } from "../providers/index.js";
import { resolveRepoPath } from "../utils.js";
import {
deactivateWorker,
getProject,
@@ -24,7 +25,6 @@ import {
readProjects,
} from "../projects.js";
import type { ToolContext } from "../types.js";
import { resolveRepoPath } from "../utils.js";
const execFileAsync = promisify(execFile);
@@ -105,17 +105,12 @@ export function createTaskCompleteTool(api: OpenClawPluginApi) {
);
}
const repoPath = resolveRepoPath(project.repo);
const { provider } = createProvider({
glabPath: (api.pluginConfig as Record<string, unknown>)?.glabPath as
| string
| undefined,
ghPath: (api.pluginConfig as Record<string, unknown>)?.ghPath as
| string
| undefined,
repoPath,
repo: project.repo,
});
const repoPath = resolveRepoPath(project.repo);
const output: Record<string, unknown> = {
success: true,
project: project.name,

View File

@@ -13,7 +13,6 @@ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
import { jsonResult } from "openclaw/plugin-sdk";
import type { ToolContext } from "../types.js";
import { readProjects } from "../projects.js";
import { resolveRepoPath } from "../utils.js";
import { createProvider } from "../providers/index.js";
import { log as auditLog } from "../audit.js";
import type { StateLabel } from "../issue-provider.js";
@@ -95,12 +94,8 @@ The issue is created with a state label (defaults to "Planning"). Returns the cr
}
// 2. Create provider
const repoPath = resolveRepoPath(project.repo);
const config = api.pluginConfig as Record<string, unknown> | undefined;
const { provider, type: providerType } = createProvider({
glabPath: config?.glabPath as string | undefined,
ghPath: config?.ghPath as string | undefined,
repoPath,
repo: project.repo,
});
// 3. Create the issue

View File

@@ -17,7 +17,6 @@ import { selectModel } from "../model-selector.js";
import { getProject, getWorker, readProjects } from "../projects.js";
import type { ToolContext } from "../types.js";
import { detectContext, generateGuardrails } from "../context-guard.js";
import { resolveRepoPath } from "../utils.js";
export function createTaskPickupTool(api: OpenClawPluginApi) {
return (ctx: ToolContext) => ({
@@ -96,15 +95,8 @@ export function createTaskPickupTool(api: OpenClawPluginApi) {
}
// 3. Fetch issue and verify state
const repoPath = resolveRepoPath(project.repo);
const { provider } = createProvider({
glabPath: (api.pluginConfig as Record<string, unknown>)?.glabPath as
| string
| undefined,
ghPath: (api.pluginConfig as Record<string, unknown>)?.ghPath as
| string
| undefined,
repoPath,
repo: project.repo,
});
const issue = await provider.getIssue(issueId);

View File

@@ -9,19 +9,23 @@
"type": "object",
"description": "Model mapping per developer tier (junior, medior, senior, qa)",
"properties": {
"junior": { "type": "string", "description": "Junior dev model (default: anthropic/claude-haiku-4-5)" },
"medior": { "type": "string", "description": "Medior dev model (default: anthropic/claude-sonnet-4-5)" },
"senior": { "type": "string", "description": "Senior dev model (default: anthropic/claude-opus-4-5)" },
"qa": { "type": "string", "description": "QA engineer model (default: anthropic/claude-sonnet-4-5)" }
"junior": {
"type": "string",
"description": "Junior dev model (default: anthropic/claude-haiku-4-5)"
},
"medior": {
"type": "string",
"description": "Medior dev model (default: anthropic/claude-sonnet-4-5)"
},
"senior": {
"type": "string",
"description": "Senior dev model (default: anthropic/claude-opus-4-5)"
},
"qa": {
"type": "string",
"description": "QA engineer model (default: anthropic/claude-sonnet-4-5)"
}
}
},
"glabPath": {
"type": "string",
"description": "Path to glab CLI binary. Defaults to 'glab' on PATH."
},
"ghPath": {
"type": "string",
"description": "Path to gh CLI binary. Defaults to 'gh' on PATH."
}
}
}