refactor(extensions): simplify lib helpers, tool registration and kit-doctor
Behavior-preserving cleanups: - extract shared resolveBaseUrl helper for jira/confluence base-URL logic - extract shared registerTool helper; port jira/gitlab/confluence tools to it - make scanSecrets declarative (filter/map) - collapse ok/warn pair into status() and drop double existsSync in kit-doctor Typecheck clean; npm test 71 PASS, 0 FAIL.
This commit is contained in:
+53
-57
@@ -6,72 +6,68 @@
|
||||
* DISABLE: remove/rename this file from extensions/.
|
||||
*/
|
||||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
import { mrCreate, pipelineStatus, codeSearch, deriveProjectFromOrigin } from "./lib/gitlab.ts";
|
||||
import { registerTool, type ToolSpec } from "./lib/tools.ts";
|
||||
import { mrCreate, pipelineStatus, codeSearch } from "./lib/gitlab.ts";
|
||||
|
||||
export default function gitlabToolsExtension(pi: ExtensionAPI) {
|
||||
const register = (name: string, description: string, parameters: Record<string, unknown>, run: (p: any) => Promise<unknown>) => {
|
||||
pi.registerTool({
|
||||
name,
|
||||
label: name,
|
||||
description,
|
||||
parameters: parameters as any,
|
||||
async execute(_id: string, params: unknown) {
|
||||
try {
|
||||
const out = await run(params ?? {});
|
||||
return { content: [{ type: "text", text: JSON.stringify(out ?? {}, null, 2) }], details: {} };
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
return { content: [{ type: "text", text: `gitlab error: ${msg}` }], isError: true, details: {} };
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
register(
|
||||
"gitlab_mr_create",
|
||||
"Создать merge request в GitLab. Проект определяется из git remote origin (или укажи project).",
|
||||
const tools: ToolSpec[] = [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
title: { type: "string", description: "Заголовок MR" },
|
||||
sourceBranch: { type: "string", description: "Ветка-источник (по умолчанию текущая)" },
|
||||
targetBranch: { type: "string", description: "Целевая ветка (по умолчанию main)" },
|
||||
project: { type: "string", description: "Группа/репозиторий, например group/name. Если пусто — берётся из origin" },
|
||||
removeSourceBranch: { type: "boolean", description: "Удалить ветку после мержа (default true)" },
|
||||
mergeWhenPipelineSucceeds: { type: "boolean", description: "Мержить после успешного пайплайна" },
|
||||
name: "gitlab_mr_create",
|
||||
description: "Создать merge request в GitLab. Проект определяется из git remote origin (или укажи project).",
|
||||
errorPrefix: "gitlab",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
title: { type: "string", description: "Заголовок MR" },
|
||||
sourceBranch: { type: "string", description: "Ветка-источник (по умолчанию текущая)" },
|
||||
targetBranch: { type: "string", description: "Целевая ветка (по умолчанию main)" },
|
||||
project: { type: "string", description: "Группа/репозиторий, например group/name. Если пусто — берётся из origin" },
|
||||
removeSourceBranch: { type: "boolean", description: "Удалить ветку после мержа (default true)" },
|
||||
mergeWhenPipelineSucceeds: { type: "boolean", description: "Мержить после успешного пайплайна" },
|
||||
},
|
||||
required: ["title"],
|
||||
},
|
||||
required: ["title"],
|
||||
run: async (p) =>
|
||||
mrCreate({
|
||||
title: p.title,
|
||||
sourceBranch: p.sourceBranch || undefined,
|
||||
targetBranch: p.targetBranch,
|
||||
project: p.project,
|
||||
removeSourceBranch: p.removeSourceBranch,
|
||||
mergeWhenPipelineSucceeds: p.mergeWhenPipelineSucceeds,
|
||||
}),
|
||||
},
|
||||
async (p) => mrCreate({ title: p.title, sourceBranch: p.sourceBranch || undefined, targetBranch: p.targetBranch, project: p.project, removeSourceBranch: p.removeSourceBranch, mergeWhenPipelineSucceeds: p.mergeWhenPipelineSucceeds }),
|
||||
);
|
||||
|
||||
register(
|
||||
"gitlab_pipeline_status",
|
||||
"Показать статусы CI/CD пайплайнов проекта GitLab (по ветке).",
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
project: { type: "string", description: "Группа/репозиторий (обязательно; например group/name)" },
|
||||
ref: { type: "string", description: "Ветка/тег, по которому фильтровать" },
|
||||
perPage: { type: "number", description: "Сколько последних пайплайнов (default 10)" },
|
||||
name: "gitlab_pipeline_status",
|
||||
description: "Показать статусы CI/CD пайплайнов проекта GitLab (по ветке).",
|
||||
errorPrefix: "gitlab",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
project: { type: "string", description: "Группа/репозиторий (обязательно; например group/name)" },
|
||||
ref: { type: "string", description: "Ветка/тег, по которому фильтровать" },
|
||||
perPage: { type: "number", description: "Сколько последних пайплайнов (default 10)" },
|
||||
},
|
||||
required: ["project"],
|
||||
},
|
||||
required: ["project"],
|
||||
run: async (p) => pipelineStatus(p.project, { ref: p.ref, perPage: p.perPage }),
|
||||
},
|
||||
async (p) => pipelineStatus(p.project, { ref: p.ref, perPage: p.perPage }),
|
||||
);
|
||||
|
||||
register(
|
||||
"gitlab_code_search",
|
||||
"Поиск по коду в GitLab (blobs). Требует scope api/read_api у токена.",
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
query: { type: "string", description: "Строка поиска (до 512 символов)" },
|
||||
project: { type: "string", description: "Ограничить поиск группой/репозиторием" },
|
||||
perPage: { type: "number", description: "Макс. результатов (default 20)" },
|
||||
name: "gitlab_code_search",
|
||||
description: "Поиск по коду в GitLab (blobs). Требует scope api/read_api у токена.",
|
||||
errorPrefix: "gitlab",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
query: { type: "string", description: "Строка поиска (до 512 символов)" },
|
||||
project: { type: "string", description: "Ограничить поиск группой/репозиторием" },
|
||||
perPage: { type: "number", description: "Макс. результатов (default 20)" },
|
||||
},
|
||||
required: ["query"],
|
||||
},
|
||||
required: ["query"],
|
||||
run: async (p) => codeSearch(p.query, { project: p.project, perPage: p.perPage }),
|
||||
},
|
||||
async (p) => codeSearch(p.query, { project: p.project, perPage: p.perPage }),
|
||||
);
|
||||
];
|
||||
|
||||
for (const t of tools) registerTool(pi, t);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user