opencode-gitlab-dap 1.13.0 → 1.14.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/dist/index.cjs +182 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +182 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3947,6 +3947,10 @@ ${e.content}`).join("\n\n---\n\n");
|
|
|
3947
3947
|
|
|
3948
3948
|
// src/tools/skill-tools.ts
|
|
3949
3949
|
var import_plugin6 = require("@opencode-ai/plugin");
|
|
3950
|
+
var import_child_process = require("child_process");
|
|
3951
|
+
var import_fs2 = require("fs");
|
|
3952
|
+
var import_path2 = require("path");
|
|
3953
|
+
var import_os2 = require("os");
|
|
3950
3954
|
var z6 = import_plugin6.tool.schema;
|
|
3951
3955
|
var PREFIX2 = "agents";
|
|
3952
3956
|
var SKILLS_PREFIX = `${PREFIX2}/skills`;
|
|
@@ -4077,6 +4081,83 @@ async function upsertPage(instanceUrl, token, scope, id, slug, content) {
|
|
|
4077
4081
|
await createWikiPage(instanceUrl, token, scope, id, slug, content);
|
|
4078
4082
|
}
|
|
4079
4083
|
}
|
|
4084
|
+
function searchSkillsSh(query) {
|
|
4085
|
+
try {
|
|
4086
|
+
const raw = (0, import_child_process.execSync)(`npx skills find ${JSON.stringify(query)}`, {
|
|
4087
|
+
timeout: 3e4,
|
|
4088
|
+
encoding: "utf-8",
|
|
4089
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
4090
|
+
});
|
|
4091
|
+
const lines = raw.split("\n");
|
|
4092
|
+
const results = [];
|
|
4093
|
+
for (let i = 0; i < lines.length; i++) {
|
|
4094
|
+
const clean = lines[i].replace(/\x1b\[[0-9;]*m/g, "").trim();
|
|
4095
|
+
const match = clean.match(/^(\S+\/\S+@\S+)\s+(.+installs?)$/);
|
|
4096
|
+
if (match) {
|
|
4097
|
+
const urlLine = (lines[i + 1] ?? "").replace(/\x1b\[[0-9;]*m/g, "").trim();
|
|
4098
|
+
const url = urlLine.startsWith("\u2514 ") ? urlLine.slice(2) : urlLine;
|
|
4099
|
+
results.push({ identifier: match[1], installs: match[2], url });
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
4102
|
+
return results;
|
|
4103
|
+
} catch {
|
|
4104
|
+
return [];
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
function downloadSkillFromSkillsSh(identifier) {
|
|
4108
|
+
const tmp = (0, import_fs2.mkdtempSync)((0, import_path2.join)((0, import_os2.tmpdir)(), "skill-install-"));
|
|
4109
|
+
try {
|
|
4110
|
+
(0, import_child_process.execSync)(`npx skills add ${JSON.stringify(identifier)} -y --copy`, {
|
|
4111
|
+
timeout: 6e4,
|
|
4112
|
+
cwd: tmp,
|
|
4113
|
+
encoding: "utf-8",
|
|
4114
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
4115
|
+
});
|
|
4116
|
+
const agentsDir = (0, import_path2.join)(tmp, ".agents", "skills");
|
|
4117
|
+
if (!(0, import_fs2.statSync)(agentsDir).isDirectory()) return null;
|
|
4118
|
+
const dirs = (0, import_fs2.readdirSync)(agentsDir);
|
|
4119
|
+
if (dirs.length === 0) return null;
|
|
4120
|
+
const skillName = dirs[0];
|
|
4121
|
+
const skillDir = (0, import_path2.join)(agentsDir, skillName);
|
|
4122
|
+
const skillMd = (0, import_path2.join)(skillDir, "SKILL.md");
|
|
4123
|
+
let mainContent;
|
|
4124
|
+
try {
|
|
4125
|
+
mainContent = (0, import_fs2.readFileSync)(skillMd, "utf-8");
|
|
4126
|
+
} catch {
|
|
4127
|
+
return null;
|
|
4128
|
+
}
|
|
4129
|
+
let description = "";
|
|
4130
|
+
const descMatch = mainContent.match(/^---\s*\n[\s\S]*?description:\s*(.+)\n[\s\S]*?---/);
|
|
4131
|
+
if (descMatch) {
|
|
4132
|
+
description = descMatch[1].trim();
|
|
4133
|
+
} else {
|
|
4134
|
+
const firstParagraph = mainContent.replace(/^---[\s\S]*?---\s*\n/, "").replace(/^#[^\n]*\n+/, "").split("\n\n")[0].replace(/\n/g, " ").trim();
|
|
4135
|
+
description = firstParagraph.slice(0, 200);
|
|
4136
|
+
}
|
|
4137
|
+
const files = [];
|
|
4138
|
+
const walkStack = [{ dir: skillDir, prefix: "" }];
|
|
4139
|
+
while (walkStack.length > 0) {
|
|
4140
|
+
const { dir, prefix } = walkStack.pop();
|
|
4141
|
+
for (const entry of (0, import_fs2.readdirSync)(dir)) {
|
|
4142
|
+
const full = (0, import_path2.join)(dir, entry);
|
|
4143
|
+
const rel = prefix ? `${prefix}/${entry}` : entry;
|
|
4144
|
+
if ((0, import_fs2.statSync)(full).isDirectory()) {
|
|
4145
|
+
walkStack.push({ dir: full, prefix: rel });
|
|
4146
|
+
} else if (entry !== "SKILL.md") {
|
|
4147
|
+
files.push({ path: rel, content: (0, import_fs2.readFileSync)(full, "utf-8") });
|
|
4148
|
+
}
|
|
4149
|
+
}
|
|
4150
|
+
}
|
|
4151
|
+
return { name: skillName, content: mainContent, description, files };
|
|
4152
|
+
} catch {
|
|
4153
|
+
return null;
|
|
4154
|
+
} finally {
|
|
4155
|
+
try {
|
|
4156
|
+
(0, import_fs2.rmSync)(tmp, { recursive: true, force: true });
|
|
4157
|
+
} catch {
|
|
4158
|
+
}
|
|
4159
|
+
}
|
|
4160
|
+
}
|
|
4080
4161
|
function makeSkillTools(ctx) {
|
|
4081
4162
|
function authAndValidate(projectId) {
|
|
4082
4163
|
const auth = ctx.ensureAuth();
|
|
@@ -4244,55 +4325,125 @@ Load with: gitlab_skill_load_reference(name="${args.name}", reference="<name>")`
|
|
|
4244
4325
|
}
|
|
4245
4326
|
}),
|
|
4246
4327
|
gitlab_skill_discover: (0, import_plugin6.tool)({
|
|
4247
|
-
description: "Search for skills
|
|
4328
|
+
description: "Search for skills in the group wiki and the skills.sh public registry.\nGroup wiki skills are searched first, then skills.sh for community skills.\nUse gitlab_skill_install to install a discovered skill into your project.",
|
|
4248
4329
|
args: {
|
|
4249
4330
|
project_id: z6.string().describe(PROJECT_ID_DESC2),
|
|
4250
4331
|
query: z6.string().describe("Search query (matches skill name and description)"),
|
|
4251
|
-
group_id: z6.string().describe("Group path to search for shared skills")
|
|
4332
|
+
group_id: z6.string().optional().describe("Group path to search for shared skills (optional)")
|
|
4252
4333
|
},
|
|
4253
4334
|
execute: async (args) => {
|
|
4254
4335
|
const auth = authAndValidate(args.project_id);
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
${entries.map((e) => `- ${e.name}: ${e.description}`).join("\n")}`;
|
|
4273
|
-
}
|
|
4274
|
-
return `Found ${matches.length} skill(s) in group "${args.group_id}":
|
|
4336
|
+
const sections = [];
|
|
4337
|
+
if (args.group_id) {
|
|
4338
|
+
try {
|
|
4339
|
+
const entries = await readIndex(
|
|
4340
|
+
auth.instanceUrl,
|
|
4341
|
+
auth.token,
|
|
4342
|
+
"groups",
|
|
4343
|
+
args.group_id,
|
|
4344
|
+
SKILLS_INDEX
|
|
4345
|
+
);
|
|
4346
|
+
const q = args.query.toLowerCase();
|
|
4347
|
+
const matches = entries.filter(
|
|
4348
|
+
(e) => e.name.toLowerCase().includes(q) || e.description.toLowerCase().includes(q)
|
|
4349
|
+
);
|
|
4350
|
+
if (matches.length > 0) {
|
|
4351
|
+
sections.push(
|
|
4352
|
+
`### Group skills (${matches.length})
|
|
4275
4353
|
|
|
4276
4354
|
` + matches.map(
|
|
4277
|
-
|
|
4278
|
-
Install: gitlab_skill_install(name="${e.name}", group_id="${args.group_id}")
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4355
|
+
(e) => `**${e.name}**: ${e.description}
|
|
4356
|
+
Install: \`gitlab_skill_install(name="${e.name}", source="group", group_id="${args.group_id}")\``
|
|
4357
|
+
).join("\n\n")
|
|
4358
|
+
);
|
|
4359
|
+
}
|
|
4360
|
+
} catch {
|
|
4361
|
+
}
|
|
4282
4362
|
}
|
|
4363
|
+
const shResults = searchSkillsSh(args.query);
|
|
4364
|
+
if (shResults.length > 0) {
|
|
4365
|
+
sections.push(
|
|
4366
|
+
`### skills.sh (${shResults.length})
|
|
4367
|
+
|
|
4368
|
+
` + shResults.map(
|
|
4369
|
+
(r) => `**${r.identifier}** (${r.installs})
|
|
4370
|
+
${r.url}
|
|
4371
|
+
Install: \`gitlab_skill_install(name="${r.identifier}", source="skills.sh")\``
|
|
4372
|
+
).join("\n\n")
|
|
4373
|
+
);
|
|
4374
|
+
}
|
|
4375
|
+
if (sections.length === 0) {
|
|
4376
|
+
return `No skills found matching "${args.query}" in ${args.group_id ? "group wiki or " : ""}skills.sh.`;
|
|
4377
|
+
}
|
|
4378
|
+
return sections.join("\n\n---\n\n");
|
|
4283
4379
|
}
|
|
4284
4380
|
}),
|
|
4285
4381
|
gitlab_skill_install: (0, import_plugin6.tool)({
|
|
4286
|
-
description: "Install a skill from a group wiki into the project wiki.\
|
|
4382
|
+
description: "Install a skill from a group wiki or skills.sh into the project wiki.\nFor group: copies all skill pages (SKILL + references) from the group.\nFor skills.sh: downloads via npx, extracts SKILL.md and files, writes to wiki.\nUpdates the project skill index with the installed skill.",
|
|
4287
4383
|
args: {
|
|
4288
4384
|
project_id: z6.string().describe(PROJECT_ID_DESC2),
|
|
4289
|
-
name: z6.string().describe(
|
|
4290
|
-
|
|
4385
|
+
name: z6.string().describe(
|
|
4386
|
+
'Skill identifier. For group: skill name (e.g., "incident-retro"). For skills.sh: full identifier (e.g., "vercel-labs/agent-skills@nextjs-developer").'
|
|
4387
|
+
),
|
|
4388
|
+
source: z6.enum(["group", "skills.sh"]).describe('Where to install from: "group" (group wiki) or "skills.sh" (public registry)'),
|
|
4389
|
+
group_id: z6.string().optional().describe("Group path (required when source is group)"),
|
|
4291
4390
|
draft: z6.boolean().optional().describe("Install as draft (default: false)")
|
|
4292
4391
|
},
|
|
4293
4392
|
execute: async (args) => {
|
|
4294
4393
|
const auth = authAndValidate(args.project_id);
|
|
4295
4394
|
const projectScope = resolveScope2(args);
|
|
4395
|
+
const targetPrefix = args.draft ? DRAFTS_PREFIX : SKILLS_PREFIX;
|
|
4396
|
+
const targetIndex = args.draft ? DRAFTS_INDEX : SKILLS_INDEX;
|
|
4397
|
+
if (args.source === "skills.sh") {
|
|
4398
|
+
const downloaded = downloadSkillFromSkillsSh(args.name);
|
|
4399
|
+
if (!downloaded) {
|
|
4400
|
+
return `Failed to download skill "${args.name}" from skills.sh. Check that the identifier is correct (e.g., "owner/repo@skill-name").`;
|
|
4401
|
+
}
|
|
4402
|
+
const skillSlug = `${targetPrefix}/${downloaded.name}/SKILL`;
|
|
4403
|
+
try {
|
|
4404
|
+
await upsertPage(
|
|
4405
|
+
auth.instanceUrl,
|
|
4406
|
+
auth.token,
|
|
4407
|
+
projectScope.scope,
|
|
4408
|
+
projectScope.id,
|
|
4409
|
+
skillSlug,
|
|
4410
|
+
downloaded.content
|
|
4411
|
+
);
|
|
4412
|
+
let fileCount = 1;
|
|
4413
|
+
for (const file of downloaded.files) {
|
|
4414
|
+
const ext = file.path.replace(/\.[^.]+$/, "");
|
|
4415
|
+
const refSlug = `${targetPrefix}/${downloaded.name}/${ext}`;
|
|
4416
|
+
await upsertPage(
|
|
4417
|
+
auth.instanceUrl,
|
|
4418
|
+
auth.token,
|
|
4419
|
+
projectScope.scope,
|
|
4420
|
+
projectScope.id,
|
|
4421
|
+
refSlug,
|
|
4422
|
+
file.content
|
|
4423
|
+
);
|
|
4424
|
+
fileCount++;
|
|
4425
|
+
}
|
|
4426
|
+
await upsertIndexEntry(
|
|
4427
|
+
auth.instanceUrl,
|
|
4428
|
+
auth.token,
|
|
4429
|
+
projectScope.scope,
|
|
4430
|
+
projectScope.id,
|
|
4431
|
+
targetIndex,
|
|
4432
|
+
{
|
|
4433
|
+
name: downloaded.name,
|
|
4434
|
+
description: downloaded.description,
|
|
4435
|
+
source: `skills.sh:${args.name}`,
|
|
4436
|
+
draft: !!args.draft
|
|
4437
|
+
}
|
|
4438
|
+
);
|
|
4439
|
+
return `Installed skill "${downloaded.name}" from skills.sh. ${fileCount} page(s) written.`;
|
|
4440
|
+
} catch (err) {
|
|
4441
|
+
return `Error installing skill from skills.sh: ${err.message}`;
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4444
|
+
if (!args.group_id) {
|
|
4445
|
+
return 'Error: group_id is required when source is "group".';
|
|
4446
|
+
}
|
|
4296
4447
|
try {
|
|
4297
4448
|
const groupPages = await listWikiPages(
|
|
4298
4449
|
auth.instanceUrl,
|
|
@@ -4308,8 +4459,6 @@ Install: gitlab_skill_install(name="${e.name}", group_id="${args.group_id}")`
|
|
|
4308
4459
|
if (skillPages.length === 0) {
|
|
4309
4460
|
return `Skill "${args.name}" not found in group "${args.group_id}" wiki.`;
|
|
4310
4461
|
}
|
|
4311
|
-
const targetPrefix = args.draft ? DRAFTS_PREFIX : SKILLS_PREFIX;
|
|
4312
|
-
const targetIndex = args.draft ? DRAFTS_INDEX : SKILLS_INDEX;
|
|
4313
4462
|
for (const page of skillPages) {
|
|
4314
4463
|
const newSlug = page.slug.replace(SKILLS_PREFIX, targetPrefix);
|
|
4315
4464
|
await upsertPage(
|
|
@@ -4343,7 +4492,7 @@ Install: gitlab_skill_install(name="${e.name}", group_id="${args.group_id}")`
|
|
|
4343
4492
|
draft: !!args.draft
|
|
4344
4493
|
}
|
|
4345
4494
|
);
|
|
4346
|
-
return `Installed skill "${args.name}" from group "${args.group_id}"
|
|
4495
|
+
return `Installed skill "${args.name}" from group "${args.group_id}". ${skillPages.length} page(s) copied.`;
|
|
4347
4496
|
} catch (err) {
|
|
4348
4497
|
return `Error installing skill: ${err.message}`;
|
|
4349
4498
|
}
|