opencode-gitlab-dap 1.7.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -23
- package/dist/index.cjs +290 -107
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +290 -107
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2085,8 +2085,12 @@ prompts:
|
|
|
2085
2085
|
user: "Fix this vulnerability: {{vuln_data}}"
|
|
2086
2086
|
placeholder: history
|
|
2087
2087
|
\`\`\``;
|
|
2088
|
-
var
|
|
2089
|
-
|
|
2088
|
+
var PROJECT_KNOWLEDGE_HINT = `## Project Knowledge
|
|
2089
|
+
This project may have persistent memory and skills available via knowledge tools.
|
|
2090
|
+
Use gitlab_memory_load to check for existing project context (facts, decisions, patterns).
|
|
2091
|
+
Use gitlab_skill_list to discover available task-specific skills.
|
|
2092
|
+
When you learn something new about the project, use gitlab_memory_record to preserve it.
|
|
2093
|
+
When you complete a significant task, consider using gitlab_memory_log_session to log learnings.`;
|
|
2090
2094
|
|
|
2091
2095
|
// src/hooks.ts
|
|
2092
2096
|
function buildFlowSubagentPrompt(flow, projectPath, projectUrl) {
|
|
@@ -2246,7 +2250,7 @@ function makeSystemTransformHook(flowAgents, getAuthCache) {
|
|
|
2246
2250
|
}
|
|
2247
2251
|
if (getAuthCache()) {
|
|
2248
2252
|
output.system.push(AGENT_CREATION_GUIDELINES);
|
|
2249
|
-
output.system.push(
|
|
2253
|
+
output.system.push(PROJECT_KNOWLEDGE_HINT);
|
|
2250
2254
|
}
|
|
2251
2255
|
};
|
|
2252
2256
|
}
|
|
@@ -3355,7 +3359,7 @@ function makeMcpTools(getCachedAgents) {
|
|
|
3355
3359
|
};
|
|
3356
3360
|
}
|
|
3357
3361
|
|
|
3358
|
-
// src/tools/
|
|
3362
|
+
// src/tools/memory-tools.ts
|
|
3359
3363
|
import { tool as tool5 } from "@opencode-ai/plugin";
|
|
3360
3364
|
|
|
3361
3365
|
// src/wiki.ts
|
|
@@ -3436,180 +3440,358 @@ async function searchWikiPages(instanceUrl, token, scope, id, query) {
|
|
|
3436
3440
|
return handleResponse(res);
|
|
3437
3441
|
}
|
|
3438
3442
|
|
|
3439
|
-
// src/tools/
|
|
3443
|
+
// src/tools/memory-tools.ts
|
|
3440
3444
|
var z5 = tool5.schema;
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3445
|
+
var MEMORY_SLUGS = {
|
|
3446
|
+
all: ["memory/facts", "memory/decisions", "memory/patterns"],
|
|
3447
|
+
facts: ["memory/facts"],
|
|
3448
|
+
decisions: ["memory/decisions"],
|
|
3449
|
+
patterns: ["memory/patterns"]
|
|
3450
|
+
};
|
|
3451
|
+
var RECORD_SLUG = {
|
|
3452
|
+
fact: "memory/facts",
|
|
3453
|
+
decision: "memory/decisions",
|
|
3454
|
+
pattern: "memory/patterns"
|
|
3455
|
+
};
|
|
3456
|
+
function today() {
|
|
3457
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3458
|
+
}
|
|
3459
|
+
function slugify(text) {
|
|
3460
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
|
|
3461
|
+
}
|
|
3462
|
+
async function safeRead(instanceUrl, token, scope, id, slug) {
|
|
3463
|
+
try {
|
|
3464
|
+
const page = await getWikiPage(instanceUrl, token, scope, id, slug);
|
|
3465
|
+
return page.content;
|
|
3466
|
+
} catch {
|
|
3467
|
+
return null;
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
async function appendToPage(instanceUrl, token, scope, id, slug, newContent, pageTitle) {
|
|
3471
|
+
const existing = await safeRead(instanceUrl, token, scope, id, slug);
|
|
3472
|
+
if (existing !== null) {
|
|
3473
|
+
await updateWikiPage(instanceUrl, token, scope, id, slug, existing + "\n\n" + newContent);
|
|
3474
|
+
} else {
|
|
3475
|
+
const title = pageTitle ?? slug.split("/").pop() ?? slug;
|
|
3476
|
+
await createWikiPage(instanceUrl, token, scope, id, title, newContent);
|
|
3447
3477
|
}
|
|
3478
|
+
}
|
|
3479
|
+
function resolveScope(args) {
|
|
3480
|
+
if (args.scope === "groups" && args.group_id) {
|
|
3481
|
+
return { scope: "groups", id: args.group_id };
|
|
3482
|
+
}
|
|
3483
|
+
return { scope: "projects", id: args.project_id };
|
|
3484
|
+
}
|
|
3485
|
+
function makeMemoryTools(ctx) {
|
|
3448
3486
|
return {
|
|
3449
|
-
|
|
3450
|
-
description: "
|
|
3487
|
+
gitlab_memory_load: tool5({
|
|
3488
|
+
description: "Load project memory to understand context, known facts, past decisions, and observed patterns.\nUse this at the start of complex tasks to check what is already known about the project.\nReturns accumulated knowledge from previous sessions.",
|
|
3489
|
+
args: {
|
|
3490
|
+
project_id: z5.string().describe('Project path (e.g., "gitlab-org/gitlab"). Use the same value consistently.'),
|
|
3491
|
+
type: z5.enum(["all", "facts", "decisions", "patterns"]).optional().describe('Which memory to load: "all" (default), "facts", "decisions", or "patterns"'),
|
|
3492
|
+
scope: z5.enum(["projects", "groups"]).optional().describe("Scope (default: projects)"),
|
|
3493
|
+
group_id: z5.string().optional().describe("Group path (required when scope is groups)")
|
|
3494
|
+
},
|
|
3495
|
+
execute: async (args) => {
|
|
3496
|
+
const auth = ctx.ensureAuth();
|
|
3497
|
+
if (!auth) throw new Error("GitLab authentication not available");
|
|
3498
|
+
const { scope, id } = resolveScope(args);
|
|
3499
|
+
const memType = args.type ?? "all";
|
|
3500
|
+
const slugs = MEMORY_SLUGS[memType];
|
|
3501
|
+
if (!slugs) return `Unknown memory type: ${memType}`;
|
|
3502
|
+
const sections = [];
|
|
3503
|
+
for (const slug of slugs) {
|
|
3504
|
+
const content = await safeRead(auth.instanceUrl, auth.token, scope, id, slug);
|
|
3505
|
+
if (content) {
|
|
3506
|
+
const label = slug.split("/").pop();
|
|
3507
|
+
sections.push(`## ${label.charAt(0).toUpperCase() + label.slice(1)}
|
|
3508
|
+
|
|
3509
|
+
${content}`);
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
if (sections.length === 0)
|
|
3513
|
+
return "No project memory found. Use gitlab_memory_record to start building project knowledge.";
|
|
3514
|
+
return sections.join("\n\n---\n\n");
|
|
3515
|
+
}
|
|
3516
|
+
}),
|
|
3517
|
+
gitlab_memory_record: tool5({
|
|
3518
|
+
description: "Record a fact, decision, or pattern in project memory.\nFacts: stable truths about the project (e.g., deploy targets, tech stack, team conventions).\nDecisions: architectural choices with reasoning (why X was chosen over Y).\nPatterns: recurring observations that may evolve into skills over time.\nEntries are automatically timestamped.",
|
|
3451
3519
|
args: {
|
|
3452
|
-
project_id: z5.string().describe('Project path (e.g., "gitlab-org/gitlab")'),
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3520
|
+
project_id: z5.string().describe('Project path (e.g., "gitlab-org/gitlab"). Use the same value consistently.'),
|
|
3521
|
+
type: z5.enum(["fact", "decision", "pattern"]).describe("Type of knowledge to record"),
|
|
3522
|
+
content: z5.string().describe("The knowledge to record (markdown)"),
|
|
3523
|
+
scope: z5.enum(["projects", "groups"]).optional().describe("Scope (default: projects)"),
|
|
3524
|
+
group_id: z5.string().optional().describe("Group path (required when scope is groups)")
|
|
3456
3525
|
},
|
|
3457
3526
|
execute: async (args) => {
|
|
3458
3527
|
const auth = ctx.ensureAuth();
|
|
3459
3528
|
if (!auth) throw new Error("GitLab authentication not available");
|
|
3460
3529
|
const { scope, id } = resolveScope(args);
|
|
3530
|
+
const slug = RECORD_SLUG[args.type];
|
|
3531
|
+
if (!slug) return `Unknown memory type: ${args.type}`;
|
|
3532
|
+
const date = today();
|
|
3533
|
+
let formatted;
|
|
3534
|
+
if (args.type === "decision") {
|
|
3535
|
+
const firstLine = args.content.split("\n")[0];
|
|
3536
|
+
const rest = args.content.split("\n").slice(1).join("\n").trim();
|
|
3537
|
+
formatted = `## ${date}: ${firstLine}${rest ? "\n" + rest : ""}`;
|
|
3538
|
+
} else if (args.type === "fact") {
|
|
3539
|
+
formatted = `## ${date}
|
|
3540
|
+
- ${args.content.replace(/\n/g, "\n- ")}`;
|
|
3541
|
+
} else {
|
|
3542
|
+
formatted = `## ${date}
|
|
3543
|
+
${args.content}`;
|
|
3544
|
+
}
|
|
3461
3545
|
try {
|
|
3462
|
-
|
|
3463
|
-
return
|
|
3546
|
+
await appendToPage(auth.instanceUrl, auth.token, scope, id, slug, formatted);
|
|
3547
|
+
return `Recorded ${args.type} in project memory.`;
|
|
3464
3548
|
} catch (err) {
|
|
3465
|
-
return `Error
|
|
3549
|
+
return `Error recording ${args.type}: ${err.message}`;
|
|
3466
3550
|
}
|
|
3467
3551
|
}
|
|
3468
3552
|
}),
|
|
3469
|
-
|
|
3470
|
-
description: "
|
|
3553
|
+
gitlab_memory_recall: tool5({
|
|
3554
|
+
description: "Search project knowledge for relevant information.\nSearches across all memory pages, session logs, and skills.\nUse this to check if something is already known before investigating.",
|
|
3471
3555
|
args: {
|
|
3472
|
-
project_id: z5.string().describe('Project path (e.g., "gitlab-org/gitlab")'),
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
scope: z5.enum(["projects", "groups"]).optional().describe('Scope: "projects" (default) or "groups"'),
|
|
3477
|
-
group_id: z5.string().optional().describe("Group path, required when scope is groups")
|
|
3556
|
+
project_id: z5.string().describe('Project path (e.g., "gitlab-org/gitlab"). Use the same value consistently.'),
|
|
3557
|
+
query: z5.string().describe("What to search for"),
|
|
3558
|
+
scope: z5.enum(["projects", "groups"]).optional().describe("Scope (default: projects)"),
|
|
3559
|
+
group_id: z5.string().optional().describe("Group path (required when scope is groups)")
|
|
3478
3560
|
},
|
|
3479
3561
|
execute: async (args) => {
|
|
3480
3562
|
const auth = ctx.ensureAuth();
|
|
3481
3563
|
if (!auth) throw new Error("GitLab authentication not available");
|
|
3482
3564
|
const { scope, id } = resolveScope(args);
|
|
3483
3565
|
try {
|
|
3484
|
-
const
|
|
3566
|
+
const results = await searchWikiPages(
|
|
3485
3567
|
auth.instanceUrl,
|
|
3486
3568
|
auth.token,
|
|
3487
3569
|
scope,
|
|
3488
3570
|
id,
|
|
3489
|
-
args.
|
|
3490
|
-
args.content,
|
|
3491
|
-
args.title
|
|
3571
|
+
args.query
|
|
3492
3572
|
);
|
|
3493
|
-
return `
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
const
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
id,
|
|
3502
|
-
title,
|
|
3503
|
-
args.content
|
|
3504
|
-
);
|
|
3505
|
-
return `Created wiki page: ${page.slug}`;
|
|
3506
|
-
} catch (err) {
|
|
3507
|
-
return `Error writing wiki page: ${err.message}`;
|
|
3508
|
-
}
|
|
3573
|
+
if (results.length === 0) return `No knowledge found matching "${args.query}".`;
|
|
3574
|
+
return results.map((r) => {
|
|
3575
|
+
const category = r.path.startsWith("memory/") ? "memory" : r.path.startsWith("skills") ? "skill" : "other";
|
|
3576
|
+
const snippet = (r.data ?? "").slice(0, 200).replace(/\n/g, " ");
|
|
3577
|
+
return `[${category}] ${r.path}: ${snippet}`;
|
|
3578
|
+
}).join("\n\n");
|
|
3579
|
+
} catch (err) {
|
|
3580
|
+
return `Error searching knowledge: ${err.message}`;
|
|
3509
3581
|
}
|
|
3510
3582
|
}
|
|
3511
3583
|
}),
|
|
3512
|
-
|
|
3513
|
-
description: "
|
|
3584
|
+
gitlab_memory_log_session: tool5({
|
|
3585
|
+
description: "Log a session summary including what was accomplished, what was learned, and any suggestions.\nUse this at the end of significant work sessions to preserve context for future sessions.",
|
|
3514
3586
|
args: {
|
|
3515
|
-
project_id: z5.string().describe('Project path (e.g., "gitlab-org/gitlab")'),
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3587
|
+
project_id: z5.string().describe('Project path (e.g., "gitlab-org/gitlab"). Use the same value consistently.'),
|
|
3588
|
+
title: z5.string().describe('Brief session title (e.g., "fix-ai-gateway-healthcheck")'),
|
|
3589
|
+
summary: z5.string().describe(
|
|
3590
|
+
"Session summary in markdown (what happened, what was learned, what went wrong)"
|
|
3591
|
+
),
|
|
3592
|
+
scope: z5.enum(["projects", "groups"]).optional().describe("Scope (default: projects)"),
|
|
3593
|
+
group_id: z5.string().optional().describe("Group path (required when scope is groups)")
|
|
3520
3594
|
},
|
|
3521
3595
|
execute: async (args) => {
|
|
3522
3596
|
const auth = ctx.ensureAuth();
|
|
3523
3597
|
if (!auth) throw new Error("GitLab authentication not available");
|
|
3524
3598
|
const { scope, id } = resolveScope(args);
|
|
3599
|
+
const date = today();
|
|
3600
|
+
const slug = `memory/sessions/${date}-${slugify(args.title)}`;
|
|
3601
|
+
const pageTitle = `${date}: ${args.title}`;
|
|
3525
3602
|
try {
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3603
|
+
await createWikiPage(auth.instanceUrl, auth.token, scope, id, pageTitle, args.summary);
|
|
3604
|
+
return `Session logged: ${slug}`;
|
|
3605
|
+
} catch (err) {
|
|
3606
|
+
if (err.message?.includes("already exists") || err.message?.includes("422")) {
|
|
3607
|
+
try {
|
|
3608
|
+
await updateWikiPage(
|
|
3609
|
+
auth.instanceUrl,
|
|
3610
|
+
auth.token,
|
|
3611
|
+
scope,
|
|
3612
|
+
id,
|
|
3613
|
+
slug,
|
|
3614
|
+
args.summary,
|
|
3615
|
+
pageTitle
|
|
3616
|
+
);
|
|
3617
|
+
return `Session log updated: ${slug}`;
|
|
3618
|
+
} catch (err2) {
|
|
3619
|
+
return `Error logging session: ${err2.message}`;
|
|
3620
|
+
}
|
|
3537
3621
|
}
|
|
3622
|
+
return `Error logging session: ${err.message}`;
|
|
3538
3623
|
}
|
|
3539
3624
|
}
|
|
3540
|
-
})
|
|
3541
|
-
|
|
3542
|
-
|
|
3625
|
+
})
|
|
3626
|
+
};
|
|
3627
|
+
}
|
|
3628
|
+
|
|
3629
|
+
// src/tools/skill-tools.ts
|
|
3630
|
+
import { tool as tool6 } from "@opencode-ai/plugin";
|
|
3631
|
+
var z6 = tool6.schema;
|
|
3632
|
+
function resolveScope2(args) {
|
|
3633
|
+
if (args.scope === "groups" && args.group_id) {
|
|
3634
|
+
return { scope: "groups", id: args.group_id };
|
|
3635
|
+
}
|
|
3636
|
+
return { scope: "projects", id: args.project_id };
|
|
3637
|
+
}
|
|
3638
|
+
function makeSkillTools(ctx) {
|
|
3639
|
+
return {
|
|
3640
|
+
gitlab_skill_list: tool6({
|
|
3641
|
+
description: "List available project skills and optionally draft skills.\nSkills define step-by-step procedures for common tasks (e.g., incident retros, debugging, deployments).",
|
|
3543
3642
|
args: {
|
|
3544
|
-
project_id:
|
|
3545
|
-
|
|
3546
|
-
scope:
|
|
3547
|
-
group_id:
|
|
3643
|
+
project_id: z6.string().describe('Project path (e.g., "gitlab-org/gitlab"). Use the same value consistently.'),
|
|
3644
|
+
include_drafts: z6.boolean().optional().describe("Also list draft skills (default: false)"),
|
|
3645
|
+
scope: z6.enum(["projects", "groups"]).optional().describe("Scope (default: projects)"),
|
|
3646
|
+
group_id: z6.string().optional().describe("Group path (required when scope is groups)")
|
|
3548
3647
|
},
|
|
3549
3648
|
execute: async (args) => {
|
|
3550
3649
|
const auth = ctx.ensureAuth();
|
|
3551
3650
|
if (!auth) throw new Error("GitLab authentication not available");
|
|
3552
|
-
const { scope, id } =
|
|
3651
|
+
const { scope, id } = resolveScope2(args);
|
|
3553
3652
|
try {
|
|
3554
3653
|
const pages = await listWikiPages(auth.instanceUrl, auth.token, scope, id);
|
|
3555
|
-
const
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3654
|
+
const skills = pages.filter((p) => p.slug.startsWith("skills/") && p.slug !== "skills/index").map((p) => ({ name: p.slug.replace("skills/", ""), title: p.title, draft: false }));
|
|
3655
|
+
let drafts = [];
|
|
3656
|
+
if (args.include_drafts) {
|
|
3657
|
+
drafts = pages.filter(
|
|
3658
|
+
(p) => p.slug.startsWith("skills-drafts/") && p.slug !== "skills-drafts/index"
|
|
3659
|
+
).map((p) => ({
|
|
3660
|
+
name: p.slug.replace("skills-drafts/", ""),
|
|
3661
|
+
title: p.title,
|
|
3662
|
+
draft: true
|
|
3663
|
+
}));
|
|
3664
|
+
}
|
|
3665
|
+
const all = [...skills, ...drafts];
|
|
3666
|
+
if (all.length === 0) return "No skills found. Use gitlab_skill_save to create one.";
|
|
3667
|
+
return JSON.stringify(all, null, 2);
|
|
3561
3668
|
} catch (err) {
|
|
3562
|
-
return `Error listing
|
|
3669
|
+
return `Error listing skills: ${err.message}`;
|
|
3563
3670
|
}
|
|
3564
3671
|
}
|
|
3565
3672
|
}),
|
|
3566
|
-
|
|
3567
|
-
description: "
|
|
3673
|
+
gitlab_skill_load: tool6({
|
|
3674
|
+
description: "Load a specific skill by name.\nSkills contain step-by-step instructions for common tasks.\nChecks published skills first, then falls back to draft skills.",
|
|
3568
3675
|
args: {
|
|
3569
|
-
project_id:
|
|
3570
|
-
|
|
3571
|
-
scope:
|
|
3572
|
-
group_id:
|
|
3676
|
+
project_id: z6.string().describe('Project path (e.g., "gitlab-org/gitlab"). Use the same value consistently.'),
|
|
3677
|
+
name: z6.string().describe('Skill name (e.g., "incident-retro", "helm-rollback")'),
|
|
3678
|
+
scope: z6.enum(["projects", "groups"]).optional().describe("Scope (default: projects)"),
|
|
3679
|
+
group_id: z6.string().optional().describe("Group path (required when scope is groups)")
|
|
3573
3680
|
},
|
|
3574
3681
|
execute: async (args) => {
|
|
3575
3682
|
const auth = ctx.ensureAuth();
|
|
3576
3683
|
if (!auth) throw new Error("GitLab authentication not available");
|
|
3577
|
-
const { scope, id } =
|
|
3684
|
+
const { scope, id } = resolveScope2(args);
|
|
3578
3685
|
try {
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3686
|
+
const page = await getWikiPage(
|
|
3687
|
+
auth.instanceUrl,
|
|
3688
|
+
auth.token,
|
|
3689
|
+
scope,
|
|
3690
|
+
id,
|
|
3691
|
+
`skills/${args.name}`
|
|
3692
|
+
);
|
|
3693
|
+
return page.content;
|
|
3694
|
+
} catch {
|
|
3695
|
+
try {
|
|
3696
|
+
const draft = await getWikiPage(
|
|
3697
|
+
auth.instanceUrl,
|
|
3698
|
+
auth.token,
|
|
3699
|
+
scope,
|
|
3700
|
+
id,
|
|
3701
|
+
`skills-drafts/${args.name}`
|
|
3702
|
+
);
|
|
3703
|
+
return `[DRAFT SKILL]
|
|
3704
|
+
|
|
3705
|
+
${draft.content}`;
|
|
3706
|
+
} catch {
|
|
3707
|
+
return `Skill "${args.name}" not found. Use gitlab_skill_list to see available skills.`;
|
|
3708
|
+
}
|
|
3583
3709
|
}
|
|
3584
3710
|
}
|
|
3585
3711
|
}),
|
|
3586
|
-
|
|
3587
|
-
description: "
|
|
3712
|
+
gitlab_skill_save: tool6({
|
|
3713
|
+
description: "Create or update a skill.\nSkills define step-by-step procedures for common tasks.\nUse draft=true for skills that haven't been proven yet.",
|
|
3588
3714
|
args: {
|
|
3589
|
-
project_id:
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3715
|
+
project_id: z6.string().describe('Project path (e.g., "gitlab-org/gitlab"). Use the same value consistently.'),
|
|
3716
|
+
name: z6.string().describe('Skill name (e.g., "incident-retro")'),
|
|
3717
|
+
content: z6.string().describe("Skill content in markdown"),
|
|
3718
|
+
draft: z6.boolean().optional().describe("Save as draft skill (default: false)"),
|
|
3719
|
+
scope: z6.enum(["projects", "groups"]).optional().describe("Scope (default: projects)"),
|
|
3720
|
+
group_id: z6.string().optional().describe("Group path (required when scope is groups)")
|
|
3593
3721
|
},
|
|
3594
3722
|
execute: async (args) => {
|
|
3595
3723
|
const auth = ctx.ensureAuth();
|
|
3596
3724
|
if (!auth) throw new Error("GitLab authentication not available");
|
|
3597
|
-
const { scope, id } =
|
|
3725
|
+
const { scope, id } = resolveScope2(args);
|
|
3726
|
+
const prefix = args.draft ? "skills-drafts" : "skills";
|
|
3727
|
+
const slug = `${prefix}/${args.name}`;
|
|
3598
3728
|
try {
|
|
3599
|
-
|
|
3729
|
+
await updateWikiPage(
|
|
3600
3730
|
auth.instanceUrl,
|
|
3601
3731
|
auth.token,
|
|
3602
3732
|
scope,
|
|
3603
3733
|
id,
|
|
3604
|
-
|
|
3734
|
+
slug,
|
|
3735
|
+
args.content,
|
|
3736
|
+
args.name
|
|
3737
|
+
);
|
|
3738
|
+
return `Updated ${args.draft ? "draft " : ""}skill: ${args.name}`;
|
|
3739
|
+
} catch {
|
|
3740
|
+
try {
|
|
3741
|
+
await createWikiPage(auth.instanceUrl, auth.token, scope, id, args.name, args.content);
|
|
3742
|
+
return `Created ${args.draft ? "draft " : ""}skill: ${args.name}`;
|
|
3743
|
+
} catch (err) {
|
|
3744
|
+
return `Error saving skill: ${err.message}`;
|
|
3745
|
+
}
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
}),
|
|
3749
|
+
gitlab_skill_promote: tool6({
|
|
3750
|
+
description: "Promote a draft skill to published.\nMoves the skill from the drafts directory to the published skills directory.",
|
|
3751
|
+
args: {
|
|
3752
|
+
project_id: z6.string().describe('Project path (e.g., "gitlab-org/gitlab"). Use the same value consistently.'),
|
|
3753
|
+
name: z6.string().describe("Skill name to promote"),
|
|
3754
|
+
scope: z6.enum(["projects", "groups"]).optional().describe("Scope (default: projects)"),
|
|
3755
|
+
group_id: z6.string().optional().describe("Group path (required when scope is groups)")
|
|
3756
|
+
},
|
|
3757
|
+
execute: async (args) => {
|
|
3758
|
+
const auth = ctx.ensureAuth();
|
|
3759
|
+
if (!auth) throw new Error("GitLab authentication not available");
|
|
3760
|
+
const { scope, id } = resolveScope2(args);
|
|
3761
|
+
try {
|
|
3762
|
+
const draft = await getWikiPage(
|
|
3763
|
+
auth.instanceUrl,
|
|
3764
|
+
auth.token,
|
|
3765
|
+
scope,
|
|
3766
|
+
id,
|
|
3767
|
+
`skills-drafts/${args.name}`
|
|
3605
3768
|
);
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3769
|
+
try {
|
|
3770
|
+
await updateWikiPage(
|
|
3771
|
+
auth.instanceUrl,
|
|
3772
|
+
auth.token,
|
|
3773
|
+
scope,
|
|
3774
|
+
id,
|
|
3775
|
+
`skills/${args.name}`,
|
|
3776
|
+
draft.content,
|
|
3777
|
+
args.name
|
|
3778
|
+
);
|
|
3779
|
+
} catch {
|
|
3780
|
+
await createWikiPage(auth.instanceUrl, auth.token, scope, id, args.name, draft.content);
|
|
3781
|
+
}
|
|
3782
|
+
await deleteWikiPage(
|
|
3783
|
+
auth.instanceUrl,
|
|
3784
|
+
auth.token,
|
|
3785
|
+
scope,
|
|
3786
|
+
id,
|
|
3787
|
+
`skills-drafts/${args.name}`
|
|
3610
3788
|
);
|
|
3789
|
+
return `Promoted skill "${args.name}" from draft to published.`;
|
|
3611
3790
|
} catch (err) {
|
|
3612
|
-
|
|
3791
|
+
if (err.message?.includes("not found") || err.message?.includes("404")) {
|
|
3792
|
+
return `Draft skill "${args.name}" not found. Use gitlab_skill_list(include_drafts=true) to see available drafts.`;
|
|
3793
|
+
}
|
|
3794
|
+
return `Error promoting skill: ${err.message}`;
|
|
3613
3795
|
}
|
|
3614
3796
|
}
|
|
3615
3797
|
})
|
|
@@ -3770,7 +3952,8 @@ var plugin = async (input) => {
|
|
|
3770
3952
|
...makeMcpTools(() => cachedAgents),
|
|
3771
3953
|
...makeCatalogCrudTools(ctx),
|
|
3772
3954
|
...makeCatalogItemTools(ctx),
|
|
3773
|
-
...
|
|
3955
|
+
...makeMemoryTools(ctx),
|
|
3956
|
+
...makeSkillTools(ctx)
|
|
3774
3957
|
}
|
|
3775
3958
|
};
|
|
3776
3959
|
};
|