78 lines
3.5 KiB
TypeScript
78 lines
3.5 KiB
TypeScript
/**
|
||
* GitLab tools — native pi tools over the self-hosted GitLab REST API (v4).
|
||
* Thin wrappers around lib/gitlab.ts.
|
||
*
|
||
* CONFIGURE: config/company.json → gitHost; env.sh → GITLAB_TOKEN (scope api).
|
||
* 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";
|
||
|
||
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).",
|
||
{
|
||
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"],
|
||
},
|
||
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)" },
|
||
},
|
||
required: ["project"],
|
||
},
|
||
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)" },
|
||
},
|
||
required: ["query"],
|
||
},
|
||
async (p) => codeSearch(p.query, { project: p.project, perPage: p.perPage }),
|
||
);
|
||
}
|