@gitlab/opencode-gitlab-plugin 1.5.4 → 1.5.6
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/CHANGELOG.md +16 -0
- package/README.md +30 -40
- package/dist/gitlab-opencode-gitlab-plugin-1.5.6.tgz +0 -0
- package/dist/index.js +483 -467
- package/package.json +1 -1
- package/dist/gitlab-opencode-gitlab-plugin-1.5.4.tgz +0 -0
package/dist/index.js
CHANGED
|
@@ -2086,33 +2086,6 @@ Returns the list of files changed with their diffs.`,
|
|
|
2086
2086
|
return JSON.stringify(changes, null, 2);
|
|
2087
2087
|
}
|
|
2088
2088
|
}),
|
|
2089
|
-
gitlab_list_mr_notes: tool({
|
|
2090
|
-
description: `List all notes/comments on a merge request using GraphQL API with pagination support.
|
|
2091
|
-
Returns all comments including system notes, code review comments, and general discussion.
|
|
2092
|
-
This is easier to read than discussions which have nested structure.
|
|
2093
|
-
|
|
2094
|
-
The response includes pagination information (pageInfo) with cursors for fetching additional pages.
|
|
2095
|
-
Use 'after' with the 'endCursor' from pageInfo to get the next page.
|
|
2096
|
-
Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
2097
|
-
args: {
|
|
2098
|
-
project_id: z.string().describe("The project ID or URL-encoded path"),
|
|
2099
|
-
mr_iid: z.number().describe("The internal ID of the merge request"),
|
|
2100
|
-
first: z.number().optional().describe("Number of items to return from the beginning (default: 20, max: 100)"),
|
|
2101
|
-
after: z.string().optional().describe("Cursor for forward pagination - use endCursor from previous response"),
|
|
2102
|
-
last: z.number().optional().describe("Number of items to return from the end (for backward pagination)"),
|
|
2103
|
-
before: z.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
|
|
2104
|
-
},
|
|
2105
|
-
execute: async (args, _ctx) => {
|
|
2106
|
-
const client = getGitLabClient();
|
|
2107
|
-
const result = await client.listMrNotes(args.project_id, args.mr_iid, {
|
|
2108
|
-
first: args.first,
|
|
2109
|
-
after: args.after,
|
|
2110
|
-
last: args.last,
|
|
2111
|
-
before: args.before
|
|
2112
|
-
});
|
|
2113
|
-
return JSON.stringify(result, null, 2);
|
|
2114
|
-
}
|
|
2115
|
-
}),
|
|
2116
2089
|
gitlab_create_merge_request: tool({
|
|
2117
2090
|
description: `Create a new merge request.
|
|
2118
2091
|
Returns the created merge request with all details.`,
|
|
@@ -2330,47 +2303,6 @@ Can filter by state, labels, assignee, milestone.`,
|
|
|
2330
2303
|
});
|
|
2331
2304
|
return JSON.stringify(issues, null, 2);
|
|
2332
2305
|
}
|
|
2333
|
-
}),
|
|
2334
|
-
gitlab_list_issue_notes: tool2({
|
|
2335
|
-
description: `List all notes/comments on an issue using GraphQL API with pagination support.
|
|
2336
|
-
Returns all comments including system notes in chronological order.
|
|
2337
|
-
|
|
2338
|
-
The response includes pagination information (pageInfo) with cursors for fetching additional pages.
|
|
2339
|
-
Use 'after' with the 'endCursor' from pageInfo to get the next page.
|
|
2340
|
-
Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
2341
|
-
args: {
|
|
2342
|
-
project_id: z2.string().describe("The project ID or URL-encoded path"),
|
|
2343
|
-
issue_iid: z2.number().describe("The internal ID of the issue"),
|
|
2344
|
-
first: z2.number().optional().describe("Number of items to return from the beginning (default: 20, max: 100)"),
|
|
2345
|
-
after: z2.string().optional().describe("Cursor for forward pagination - use endCursor from previous response"),
|
|
2346
|
-
last: z2.number().optional().describe("Number of items to return from the end (for backward pagination)"),
|
|
2347
|
-
before: z2.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
|
|
2348
|
-
},
|
|
2349
|
-
execute: async (args, _ctx) => {
|
|
2350
|
-
const client = getGitLabClient();
|
|
2351
|
-
const result = await client.listIssueNotes(args.project_id, args.issue_iid, {
|
|
2352
|
-
first: args.first,
|
|
2353
|
-
after: args.after,
|
|
2354
|
-
last: args.last,
|
|
2355
|
-
before: args.before
|
|
2356
|
-
});
|
|
2357
|
-
return JSON.stringify(result, null, 2);
|
|
2358
|
-
}
|
|
2359
|
-
}),
|
|
2360
|
-
gitlab_get_issue_note: tool2({
|
|
2361
|
-
description: `Get a single note/comment from an issue by its ID.
|
|
2362
|
-
Returns the full details of a specific note including author, body, timestamps, and metadata.
|
|
2363
|
-
Useful when you need to retrieve a specific comment without fetching all notes.`,
|
|
2364
|
-
args: {
|
|
2365
|
-
project_id: z2.string().describe("The project ID or URL-encoded path"),
|
|
2366
|
-
issue_iid: z2.number().describe("The internal ID of the issue"),
|
|
2367
|
-
note_id: z2.number().describe("The ID of the note to retrieve")
|
|
2368
|
-
},
|
|
2369
|
-
execute: async (args, _ctx) => {
|
|
2370
|
-
const client = getGitLabClient();
|
|
2371
|
-
const note = await client.getIssueNote(args.project_id, args.issue_iid, args.note_id);
|
|
2372
|
-
return JSON.stringify(note, null, 2);
|
|
2373
|
-
}
|
|
2374
2306
|
})
|
|
2375
2307
|
};
|
|
2376
2308
|
|
|
@@ -2514,47 +2446,6 @@ Removes the association between the issue and the epic.`,
|
|
|
2514
2446
|
);
|
|
2515
2447
|
return JSON.stringify(result, null, 2);
|
|
2516
2448
|
}
|
|
2517
|
-
}),
|
|
2518
|
-
gitlab_list_epic_notes: tool3({
|
|
2519
|
-
description: `List all comments/notes on an epic using GraphQL API with pagination support.
|
|
2520
|
-
Returns all comments in chronological order.
|
|
2521
|
-
|
|
2522
|
-
The response includes pagination information (pageInfo) with cursors for fetching additional pages.
|
|
2523
|
-
Use 'after' with the 'endCursor' from pageInfo to get the next page.
|
|
2524
|
-
Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
2525
|
-
args: {
|
|
2526
|
-
group_id: z3.string().describe("The group ID or URL-encoded path"),
|
|
2527
|
-
epic_iid: z3.number().describe("The internal ID of the epic"),
|
|
2528
|
-
first: z3.number().optional().describe("Number of items to return from the beginning (default: 20, max: 100)"),
|
|
2529
|
-
after: z3.string().optional().describe("Cursor for forward pagination - use endCursor from previous response"),
|
|
2530
|
-
last: z3.number().optional().describe("Number of items to return from the end (for backward pagination)"),
|
|
2531
|
-
before: z3.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
|
|
2532
|
-
},
|
|
2533
|
-
execute: async (args, _ctx) => {
|
|
2534
|
-
const client = getGitLabClient();
|
|
2535
|
-
const result = await client.listEpicNotes(args.group_id, args.epic_iid, {
|
|
2536
|
-
first: args.first,
|
|
2537
|
-
after: args.after,
|
|
2538
|
-
last: args.last,
|
|
2539
|
-
before: args.before
|
|
2540
|
-
});
|
|
2541
|
-
return JSON.stringify(result, null, 2);
|
|
2542
|
-
}
|
|
2543
|
-
}),
|
|
2544
|
-
gitlab_get_epic_note: tool3({
|
|
2545
|
-
description: `Get a single note/comment from an epic by its ID.
|
|
2546
|
-
Returns the full details of a specific note including author, body, timestamps, and metadata.
|
|
2547
|
-
Useful when you need to retrieve a specific comment without fetching all notes.`,
|
|
2548
|
-
args: {
|
|
2549
|
-
group_id: z3.string().describe("The group ID or URL-encoded path"),
|
|
2550
|
-
epic_iid: z3.number().describe("The internal ID of the epic"),
|
|
2551
|
-
note_id: z3.number().describe("The ID of the note to retrieve")
|
|
2552
|
-
},
|
|
2553
|
-
execute: async (args, _ctx) => {
|
|
2554
|
-
const client = getGitLabClient();
|
|
2555
|
-
const note = await client.getEpicNote(args.group_id, args.epic_iid, args.note_id);
|
|
2556
|
-
return JSON.stringify(note, null, 2);
|
|
2557
|
-
}
|
|
2558
2449
|
})
|
|
2559
2450
|
};
|
|
2560
2451
|
|
|
@@ -2843,10 +2734,83 @@ This is different from discussions - it returns individual comments in a flat st
|
|
|
2843
2734
|
// src/tools/search.ts
|
|
2844
2735
|
import { tool as tool6 } from "@opencode-ai/plugin";
|
|
2845
2736
|
var z6 = tool6.schema;
|
|
2737
|
+
var GENERIC_SEARCH_SCOPES = ["projects", "issues", "merge_requests", "blobs"];
|
|
2738
|
+
var SPECIALIZED_SCOPES = [
|
|
2739
|
+
"milestones",
|
|
2740
|
+
"users",
|
|
2741
|
+
"commits",
|
|
2742
|
+
"notes",
|
|
2743
|
+
"wiki_blobs",
|
|
2744
|
+
"group_projects"
|
|
2745
|
+
];
|
|
2746
|
+
var ALL_SCOPES = [...GENERIC_SEARCH_SCOPES, ...SPECIALIZED_SCOPES];
|
|
2747
|
+
var REF_SUPPORTED_SCOPES = ["commits", "wiki_blobs"];
|
|
2748
|
+
var STATE_SUPPORTED_SCOPES = ["milestones"];
|
|
2749
|
+
function validationError(param, scope) {
|
|
2750
|
+
return new Error(`Missing required parameter: '${param}' is required for scope '${scope}'`);
|
|
2751
|
+
}
|
|
2752
|
+
function invalidParamError(param, validScopes) {
|
|
2753
|
+
return new Error(
|
|
2754
|
+
`Invalid parameter: '${param}' is only valid for scopes: ${validScopes.join(", ")}`
|
|
2755
|
+
);
|
|
2756
|
+
}
|
|
2757
|
+
function validateSearchParams(scope, args) {
|
|
2758
|
+
switch (scope) {
|
|
2759
|
+
case "notes":
|
|
2760
|
+
if (!args.project_id) throw validationError("project_id", scope);
|
|
2761
|
+
break;
|
|
2762
|
+
case "group_projects":
|
|
2763
|
+
if (!args.group_id) throw validationError("group_id", scope);
|
|
2764
|
+
break;
|
|
2765
|
+
}
|
|
2766
|
+
if (args.ref && !REF_SUPPORTED_SCOPES.includes(scope)) {
|
|
2767
|
+
throw invalidParamError("ref", REF_SUPPORTED_SCOPES);
|
|
2768
|
+
}
|
|
2769
|
+
if (args.state && !STATE_SUPPORTED_SCOPES.includes(scope)) {
|
|
2770
|
+
throw invalidParamError("state", STATE_SUPPORTED_SCOPES);
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2846
2773
|
var searchTools = {
|
|
2774
|
+
/**
|
|
2775
|
+
* Unified search across all GitLab resources
|
|
2776
|
+
*
|
|
2777
|
+
* @example
|
|
2778
|
+
* // Search for issues in a project
|
|
2779
|
+
* gitlab_search({ scope: "issues", search: "bug", project_id: "my-group/project" })
|
|
2780
|
+
*
|
|
2781
|
+
* @example
|
|
2782
|
+
* // Search commits on specific branch
|
|
2783
|
+
* gitlab_search({ scope: "commits", search: "fix", ref: "main" })
|
|
2784
|
+
*
|
|
2785
|
+
* @example
|
|
2786
|
+
* // Search for projects within a group
|
|
2787
|
+
* gitlab_search({ scope: "group_projects", group_id: "gitlab-org", search: "runner" })
|
|
2788
|
+
*
|
|
2789
|
+
* @example
|
|
2790
|
+
* // Search notes/comments in a project
|
|
2791
|
+
* gitlab_search({ scope: "notes", search: "LGTM", project_id: "my-group/project" })
|
|
2792
|
+
*/
|
|
2847
2793
|
gitlab_search: tool6({
|
|
2848
|
-
description: `Search across GitLab for various resources.
|
|
2849
|
-
|
|
2794
|
+
description: `Search across GitLab for various resources with scope-specific options.
|
|
2795
|
+
|
|
2796
|
+
Scopes and their requirements:
|
|
2797
|
+
- projects: Search projects by name/description
|
|
2798
|
+
- issues: Search issues by title/description
|
|
2799
|
+
- merge_requests: Search MRs by title/description
|
|
2800
|
+
- milestones: Search milestones (supports state filter)
|
|
2801
|
+
- users: Search users by name/email
|
|
2802
|
+
- blobs: Search file content (code search)
|
|
2803
|
+
- commits: Search commits by message/author/SHA (supports ref filter)
|
|
2804
|
+
- notes: Search comments/notes (requires project_id)
|
|
2805
|
+
- wiki_blobs: Search wiki content (supports ref filter)
|
|
2806
|
+
- group_projects: Search projects within a group (requires group_id)
|
|
2807
|
+
|
|
2808
|
+
Examples:
|
|
2809
|
+
- Issues: scope="issues", search="bug", project_id="my-group/my-project"
|
|
2810
|
+
- Code: scope="blobs", search="function calculateTotal"
|
|
2811
|
+
- Commits: scope="commits", search="fix login", ref="main"
|
|
2812
|
+
- Group projects: scope="group_projects", group_id="gitlab-org", search="runner"
|
|
2813
|
+
- Notes: scope="notes", search="LGTM", project_id="my-group/my-project"`,
|
|
2850
2814
|
args: {
|
|
2851
2815
|
scope: z6.enum([
|
|
2852
2816
|
"projects",
|
|
@@ -2857,238 +2821,104 @@ Scopes: projects, issues, merge_requests, milestones, users, blobs (code), commi
|
|
|
2857
2821
|
"blobs",
|
|
2858
2822
|
"commits",
|
|
2859
2823
|
"notes",
|
|
2860
|
-
"wiki_blobs"
|
|
2861
|
-
|
|
2824
|
+
"wiki_blobs",
|
|
2825
|
+
"group_projects"
|
|
2826
|
+
]).describe("The type of resource to search"),
|
|
2862
2827
|
search: z6.string().describe("The search query"),
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
args: {
|
|
2876
|
-
search: z6.string().describe("The search query"),
|
|
2877
|
-
project_id: z6.string().optional().describe("Limit search to a specific project (optional)"),
|
|
2878
|
-
state: z6.enum(["opened", "closed", "all"]).optional().describe("Filter by issue state"),
|
|
2879
|
-
labels: z6.string().optional().describe("Comma-separated list of labels to filter by"),
|
|
2880
|
-
limit: z6.number().optional().describe("Maximum number of results (default: 20)")
|
|
2881
|
-
},
|
|
2882
|
-
execute: async (args, _ctx) => {
|
|
2883
|
-
const client = getGitLabClient();
|
|
2884
|
-
const results = await client.search("issues", args.search, args.project_id, args.limit);
|
|
2885
|
-
return JSON.stringify(results, null, 2);
|
|
2886
|
-
}
|
|
2887
|
-
}),
|
|
2888
|
-
gitlab_blob_search: tool6({
|
|
2889
|
-
description: `Search file content in repositories.
|
|
2890
|
-
Search for code/text within files across projects.`,
|
|
2891
|
-
args: {
|
|
2892
|
-
search: z6.string().describe("The search query (code/text to find)"),
|
|
2893
|
-
project_id: z6.string().optional().describe("Limit search to a specific project (optional)"),
|
|
2894
|
-
limit: z6.number().optional().describe("Maximum number of results (default: 20)")
|
|
2895
|
-
},
|
|
2896
|
-
execute: async (args, _ctx) => {
|
|
2897
|
-
const client = getGitLabClient();
|
|
2898
|
-
const results = await client.search("blobs", args.search, args.project_id, args.limit);
|
|
2899
|
-
return JSON.stringify(results, null, 2);
|
|
2900
|
-
}
|
|
2901
|
-
}),
|
|
2902
|
-
gitlab_merge_request_search: tool6({
|
|
2903
|
-
description: `Search merge requests by keyword.
|
|
2904
|
-
Specialized search for merge requests with better filtering than the generic search.`,
|
|
2905
|
-
args: {
|
|
2906
|
-
search: z6.string().describe("The search query"),
|
|
2907
|
-
project_id: z6.string().optional().describe("Limit search to a specific project (optional)"),
|
|
2908
|
-
state: z6.enum(["opened", "closed", "merged", "all"]).optional().describe("Filter by MR state"),
|
|
2909
|
-
labels: z6.string().optional().describe("Comma-separated list of labels to filter by"),
|
|
2910
|
-
limit: z6.number().optional().describe("Maximum number of results (default: 20)")
|
|
2911
|
-
},
|
|
2912
|
-
execute: async (args, _ctx) => {
|
|
2913
|
-
const client = getGitLabClient();
|
|
2914
|
-
const results = await client.search(
|
|
2915
|
-
"merge_requests",
|
|
2916
|
-
args.search,
|
|
2917
|
-
args.project_id,
|
|
2918
|
-
args.limit
|
|
2919
|
-
);
|
|
2920
|
-
return JSON.stringify(results, null, 2);
|
|
2921
|
-
}
|
|
2922
|
-
}),
|
|
2923
|
-
gitlab_commit_search: tool6({
|
|
2924
|
-
description: `Search for commits in a project or across GitLab.
|
|
2925
|
-
Returns commits matching the search query with commit details including SHA, title, message, author, and dates.
|
|
2926
|
-
|
|
2927
|
-
Supports searching by:
|
|
2928
|
-
- Commit message content
|
|
2929
|
-
- Author name or email
|
|
2930
|
-
- Commit SHA (partial or full)
|
|
2931
|
-
|
|
2932
|
-
Note: Advanced search features (Premium/Ultimate) provide better commit search capabilities.`,
|
|
2933
|
-
args: {
|
|
2934
|
-
search: z6.string().describe("The search query (commit message, author, or SHA)"),
|
|
2935
|
-
project_id: z6.string().optional().describe("Limit search to a specific project (optional)"),
|
|
2936
|
-
ref: z6.string().optional().describe("Branch or tag name to search on (defaults to default branch)"),
|
|
2937
|
-
order_by: z6.enum(["created_at"]).optional().describe("Order results by created_at (default: created_at desc)"),
|
|
2938
|
-
sort: z6.enum(["asc", "desc"]).optional().describe("Sort order (asc or desc)"),
|
|
2939
|
-
limit: z6.number().optional().describe("Maximum number of results (default: 20)")
|
|
2828
|
+
// Context parameters
|
|
2829
|
+
project_id: z6.string().optional().describe("Limit search to a specific project. Required for notes scope"),
|
|
2830
|
+
group_id: z6.string().optional().describe("Group ID or path. Required for group_projects scope"),
|
|
2831
|
+
// Common options
|
|
2832
|
+
limit: z6.number().optional().describe("Maximum number of results (default: 20)"),
|
|
2833
|
+
order_by: z6.enum(["created_at"]).optional().describe(
|
|
2834
|
+
"Order results by field (for milestones, users, commits, notes, wiki_blobs, group_projects)"
|
|
2835
|
+
),
|
|
2836
|
+
sort: z6.enum(["asc", "desc"]).optional().describe("Sort order (for milestones, users, commits, notes, wiki_blobs, group_projects)"),
|
|
2837
|
+
// Scope-specific options
|
|
2838
|
+
ref: z6.string().optional().describe("Branch or tag name (for commits, wiki_blobs scopes)"),
|
|
2839
|
+
state: z6.enum(["active", "closed", "all"]).optional().describe("Filter by state (for milestones scope)")
|
|
2940
2840
|
},
|
|
2941
2841
|
execute: async (args, _ctx) => {
|
|
2942
|
-
|
|
2943
|
-
|
|
2842
|
+
validateSearchParams(args.scope, {
|
|
2843
|
+
project_id: args.project_id,
|
|
2844
|
+
group_id: args.group_id,
|
|
2944
2845
|
ref: args.ref,
|
|
2945
|
-
|
|
2946
|
-
sort: args.sort,
|
|
2947
|
-
limit: args.limit
|
|
2948
|
-
});
|
|
2949
|
-
return JSON.stringify(results, null, 2);
|
|
2950
|
-
}
|
|
2951
|
-
}),
|
|
2952
|
-
gitlab_group_project_search: tool6({
|
|
2953
|
-
description: `Search for projects within a specific group.
|
|
2954
|
-
Returns projects matching the search query within the specified group and its subgroups.
|
|
2955
|
-
|
|
2956
|
-
Useful for:
|
|
2957
|
-
- Finding projects by name or description within a group
|
|
2958
|
-
- Discovering projects in large group hierarchies
|
|
2959
|
-
- Filtering group projects by keywords`,
|
|
2960
|
-
args: {
|
|
2961
|
-
group_id: z6.string().describe("The group ID or URL-encoded path"),
|
|
2962
|
-
search: z6.string().describe("The search query (project name or description)"),
|
|
2963
|
-
order_by: z6.enum(["created_at"]).optional().describe("Order results by created_at (default: created_at desc)"),
|
|
2964
|
-
sort: z6.enum(["asc", "desc"]).optional().describe("Sort order (asc or desc)"),
|
|
2965
|
-
limit: z6.number().optional().describe("Maximum number of results (default: 20)")
|
|
2966
|
-
},
|
|
2967
|
-
execute: async (args, _ctx) => {
|
|
2968
|
-
const client = getGitLabClient();
|
|
2969
|
-
const results = await client.searchGroupProjects(args.group_id, args.search, {
|
|
2970
|
-
order_by: args.order_by,
|
|
2971
|
-
sort: args.sort,
|
|
2972
|
-
limit: args.limit
|
|
2973
|
-
});
|
|
2974
|
-
return JSON.stringify(results, null, 2);
|
|
2975
|
-
}
|
|
2976
|
-
}),
|
|
2977
|
-
gitlab_milestone_search: tool6({
|
|
2978
|
-
description: `Search for milestones in a project or across GitLab.
|
|
2979
|
-
Returns milestones matching the search query with details including title, description, state, and dates.
|
|
2980
|
-
|
|
2981
|
-
Useful for:
|
|
2982
|
-
- Finding milestones by title or description
|
|
2983
|
-
- Discovering active or closed milestones
|
|
2984
|
-
- Planning and tracking project milestones`,
|
|
2985
|
-
args: {
|
|
2986
|
-
search: z6.string().describe("The search query (milestone title or description)"),
|
|
2987
|
-
project_id: z6.string().optional().describe("Limit search to a specific project (optional)"),
|
|
2988
|
-
state: z6.enum(["active", "closed", "all"]).optional().describe("Filter by milestone state"),
|
|
2989
|
-
order_by: z6.enum(["created_at"]).optional().describe("Order results by created_at (default: created_at desc)"),
|
|
2990
|
-
sort: z6.enum(["asc", "desc"]).optional().describe("Sort order (asc or desc)"),
|
|
2991
|
-
limit: z6.number().optional().describe("Maximum number of results (default: 20)")
|
|
2992
|
-
},
|
|
2993
|
-
execute: async (args, _ctx) => {
|
|
2994
|
-
const client = getGitLabClient();
|
|
2995
|
-
const results = await client.searchMilestones(args.search, args.project_id, {
|
|
2996
|
-
state: args.state,
|
|
2997
|
-
order_by: args.order_by,
|
|
2998
|
-
sort: args.sort,
|
|
2999
|
-
limit: args.limit
|
|
3000
|
-
});
|
|
3001
|
-
return JSON.stringify(results, null, 2);
|
|
3002
|
-
}
|
|
3003
|
-
}),
|
|
3004
|
-
gitlab_note_search: tool6({
|
|
3005
|
-
description: `Search for notes/comments in a project.
|
|
3006
|
-
Returns notes (comments) matching the search query from issues, merge requests, commits, and snippets.
|
|
3007
|
-
|
|
3008
|
-
Useful for:
|
|
3009
|
-
- Finding specific comments or discussions
|
|
3010
|
-
- Tracking feedback and review comments
|
|
3011
|
-
- Searching for mentions or keywords in conversations
|
|
3012
|
-
|
|
3013
|
-
Note: This scope requires Premium or Ultimate tier with advanced search enabled.`,
|
|
3014
|
-
args: {
|
|
3015
|
-
search: z6.string().describe("The search query (comment text)"),
|
|
3016
|
-
project_id: z6.string().describe("The project ID or URL-encoded path to search in"),
|
|
3017
|
-
order_by: z6.enum(["created_at"]).optional().describe("Order results by created_at (default: created_at desc)"),
|
|
3018
|
-
sort: z6.enum(["asc", "desc"]).optional().describe("Sort order (asc or desc)"),
|
|
3019
|
-
limit: z6.number().optional().describe("Maximum number of results (default: 20)")
|
|
3020
|
-
},
|
|
3021
|
-
execute: async (args, _ctx) => {
|
|
3022
|
-
const client = getGitLabClient();
|
|
3023
|
-
const results = await client.searchNotes(args.search, args.project_id, {
|
|
3024
|
-
order_by: args.order_by,
|
|
3025
|
-
sort: args.sort,
|
|
3026
|
-
limit: args.limit
|
|
2846
|
+
state: args.state
|
|
3027
2847
|
});
|
|
3028
|
-
return JSON.stringify(results, null, 2);
|
|
3029
|
-
}
|
|
3030
|
-
}),
|
|
3031
|
-
gitlab_user_search: tool6({
|
|
3032
|
-
description: `Search for users by name or email across GitLab.
|
|
3033
|
-
Returns users matching the search query with details including username, name, state, and avatar.
|
|
3034
|
-
|
|
3035
|
-
Useful for:
|
|
3036
|
-
- Finding users to assign to issues or merge requests
|
|
3037
|
-
- Looking up user information by name or email
|
|
3038
|
-
- Discovering team members and collaborators`,
|
|
3039
|
-
args: {
|
|
3040
|
-
search: z6.string().describe("The search query (user name or email)"),
|
|
3041
|
-
project_id: z6.string().optional().describe("Limit search to project members (optional)"),
|
|
3042
|
-
order_by: z6.enum(["created_at"]).optional().describe("Order results by created_at (default: created_at desc)"),
|
|
3043
|
-
sort: z6.enum(["asc", "desc"]).optional().describe("Sort order (asc or desc)"),
|
|
3044
|
-
limit: z6.number().optional().describe("Maximum number of results (default: 20)")
|
|
3045
|
-
},
|
|
3046
|
-
execute: async (args, _ctx) => {
|
|
3047
|
-
const client = getGitLabClient();
|
|
3048
|
-
const results = await client.searchUsers(args.search, args.project_id, {
|
|
3049
|
-
order_by: args.order_by,
|
|
3050
|
-
sort: args.sort,
|
|
3051
|
-
limit: args.limit
|
|
3052
|
-
});
|
|
3053
|
-
return JSON.stringify(results, null, 2);
|
|
3054
|
-
}
|
|
3055
|
-
}),
|
|
3056
|
-
gitlab_wiki_blob_search: tool6({
|
|
3057
|
-
description: `Search for wiki content (blobs) in a project or across GitLab.
|
|
3058
|
-
Returns wiki pages matching the search query with content snippets and file information.
|
|
3059
|
-
|
|
3060
|
-
Supports advanced filters (use in search query):
|
|
3061
|
-
- filename:some_name* - Filter by filename with wildcards
|
|
3062
|
-
- path:some/path* - Filter by path with wildcards
|
|
3063
|
-
- extension:md - Filter by file extension
|
|
3064
|
-
|
|
3065
|
-
Examples:
|
|
3066
|
-
- "installation" - Search for "installation" in wiki content
|
|
3067
|
-
- "setup filename:getting-started*" - Search in files starting with "getting-started"
|
|
3068
|
-
- "api extension:md" - Search for "api" in markdown files
|
|
3069
|
-
|
|
3070
|
-
Note: Advanced search (Premium/Ultimate) provides better wiki search capabilities.`,
|
|
3071
|
-
args: {
|
|
3072
|
-
search: z6.string().describe(
|
|
3073
|
-
"The search query (supports filters: filename:, path:, extension: with wildcards)"
|
|
3074
|
-
),
|
|
3075
|
-
project_id: z6.string().optional().describe("Limit search to a specific project (optional)"),
|
|
3076
|
-
ref: z6.string().optional().describe("Branch or tag name to search on (defaults to default branch)"),
|
|
3077
|
-
order_by: z6.enum(["created_at"]).optional().describe("Order results by created_at (default: created_at desc)"),
|
|
3078
|
-
sort: z6.enum(["asc", "desc"]).optional().describe("Sort order (asc or desc)"),
|
|
3079
|
-
limit: z6.number().optional().describe("Maximum number of results (default: 20)")
|
|
3080
|
-
},
|
|
3081
|
-
execute: async (args, _ctx) => {
|
|
3082
2848
|
const client = getGitLabClient();
|
|
3083
|
-
const
|
|
3084
|
-
ref: args.ref,
|
|
2849
|
+
const commonOptions = {
|
|
3085
2850
|
order_by: args.order_by,
|
|
3086
2851
|
sort: args.sort,
|
|
3087
2852
|
limit: args.limit
|
|
3088
|
-
}
|
|
3089
|
-
|
|
2853
|
+
};
|
|
2854
|
+
switch (args.scope) {
|
|
2855
|
+
// Generic search API scopes
|
|
2856
|
+
case "projects":
|
|
2857
|
+
case "issues":
|
|
2858
|
+
case "merge_requests":
|
|
2859
|
+
case "blobs":
|
|
2860
|
+
return JSON.stringify(
|
|
2861
|
+
await client.search(args.scope, args.search, args.project_id, args.limit),
|
|
2862
|
+
null,
|
|
2863
|
+
2
|
|
2864
|
+
);
|
|
2865
|
+
// Specialized scopes with dedicated client methods
|
|
2866
|
+
case "milestones":
|
|
2867
|
+
return JSON.stringify(
|
|
2868
|
+
await client.searchMilestones(args.search, args.project_id, {
|
|
2869
|
+
...commonOptions,
|
|
2870
|
+
state: args.state
|
|
2871
|
+
}),
|
|
2872
|
+
null,
|
|
2873
|
+
2
|
|
2874
|
+
);
|
|
2875
|
+
case "users":
|
|
2876
|
+
return JSON.stringify(
|
|
2877
|
+
await client.searchUsers(args.search, args.project_id, commonOptions),
|
|
2878
|
+
null,
|
|
2879
|
+
2
|
|
2880
|
+
);
|
|
2881
|
+
case "commits":
|
|
2882
|
+
return JSON.stringify(
|
|
2883
|
+
await client.searchCommits(args.search, args.project_id, {
|
|
2884
|
+
...commonOptions,
|
|
2885
|
+
ref: args.ref
|
|
2886
|
+
}),
|
|
2887
|
+
null,
|
|
2888
|
+
2
|
|
2889
|
+
);
|
|
2890
|
+
case "notes":
|
|
2891
|
+
return JSON.stringify(
|
|
2892
|
+
await client.searchNotes(args.search, args.project_id, commonOptions),
|
|
2893
|
+
null,
|
|
2894
|
+
2
|
|
2895
|
+
);
|
|
2896
|
+
case "wiki_blobs":
|
|
2897
|
+
return JSON.stringify(
|
|
2898
|
+
await client.searchWikiBlobs(args.search, args.project_id, {
|
|
2899
|
+
...commonOptions,
|
|
2900
|
+
ref: args.ref
|
|
2901
|
+
}),
|
|
2902
|
+
null,
|
|
2903
|
+
2
|
|
2904
|
+
);
|
|
2905
|
+
case "group_projects":
|
|
2906
|
+
return JSON.stringify(
|
|
2907
|
+
await client.searchGroupProjects(args.group_id, args.search, commonOptions),
|
|
2908
|
+
null,
|
|
2909
|
+
2
|
|
2910
|
+
);
|
|
2911
|
+
default:
|
|
2912
|
+
throw new Error(
|
|
2913
|
+
`Invalid scope '${args.scope}'. Must be one of: ${ALL_SCOPES.join(", ")}`
|
|
2914
|
+
);
|
|
2915
|
+
}
|
|
3090
2916
|
}
|
|
3091
2917
|
}),
|
|
2918
|
+
/**
|
|
2919
|
+
* Search GitLab official documentation
|
|
2920
|
+
* Separate tool because it uses a completely different API (docs.gitlab.com)
|
|
2921
|
+
*/
|
|
3092
2922
|
gitlab_documentation_search: tool6({
|
|
3093
2923
|
description: `Search GitLab official documentation at docs.gitlab.com.
|
|
3094
2924
|
Returns relevant documentation pages matching the search query.
|
|
@@ -3320,43 +3150,11 @@ Requires Developer role or higher.`,
|
|
|
3320
3150
|
})
|
|
3321
3151
|
};
|
|
3322
3152
|
|
|
3323
|
-
// src/tools/
|
|
3153
|
+
// src/tools/todos.ts
|
|
3324
3154
|
import { tool as tool9 } from "@opencode-ai/plugin";
|
|
3325
3155
|
var z9 = tool9.schema;
|
|
3326
|
-
var snippetTools = {
|
|
3327
|
-
gitlab_list_snippet_notes: tool9({
|
|
3328
|
-
description: `List all notes/comments on a project snippet using GraphQL API with pagination support.
|
|
3329
|
-
Returns all comments including system notes in chronological order.
|
|
3330
|
-
|
|
3331
|
-
The response includes pagination information (pageInfo) with cursors for fetching additional pages.
|
|
3332
|
-
Use 'after' with the 'endCursor' from pageInfo to get the next page.
|
|
3333
|
-
Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
3334
|
-
args: {
|
|
3335
|
-
project_id: z9.string().describe("The project ID or URL-encoded path"),
|
|
3336
|
-
snippet_id: z9.number().describe("The ID of the snippet"),
|
|
3337
|
-
first: z9.number().optional().describe("Number of items to return from the beginning (default: 20, max: 100)"),
|
|
3338
|
-
after: z9.string().optional().describe("Cursor for forward pagination - use endCursor from previous response"),
|
|
3339
|
-
last: z9.number().optional().describe("Number of items to return from the end (for backward pagination)"),
|
|
3340
|
-
before: z9.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
|
|
3341
|
-
},
|
|
3342
|
-
execute: async (args, _ctx) => {
|
|
3343
|
-
const client = getGitLabClient();
|
|
3344
|
-
const result = await client.listSnippetNotes(args.project_id, args.snippet_id, {
|
|
3345
|
-
first: args.first,
|
|
3346
|
-
after: args.after,
|
|
3347
|
-
last: args.last,
|
|
3348
|
-
before: args.before
|
|
3349
|
-
});
|
|
3350
|
-
return JSON.stringify(result, null, 2);
|
|
3351
|
-
}
|
|
3352
|
-
})
|
|
3353
|
-
};
|
|
3354
|
-
|
|
3355
|
-
// src/tools/todos.ts
|
|
3356
|
-
import { tool as tool10 } from "@opencode-ai/plugin";
|
|
3357
|
-
var z10 = tool10.schema;
|
|
3358
3156
|
var todoTools = {
|
|
3359
|
-
gitlab_list_todos:
|
|
3157
|
+
gitlab_list_todos: tool9({
|
|
3360
3158
|
description: `List TODO items for the current user using GraphQL API with pagination support.
|
|
3361
3159
|
Returns a list of pending or done TODO items assigned to the authenticated user.
|
|
3362
3160
|
TODOs are created when you are assigned to an issue/MR, mentioned in a comment, or when someone requests your review.
|
|
@@ -3365,7 +3163,7 @@ The response includes pagination information (pageInfo) with cursors for fetchin
|
|
|
3365
3163
|
Use 'after' with the 'endCursor' from pageInfo to get the next page.
|
|
3366
3164
|
Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
3367
3165
|
args: {
|
|
3368
|
-
action:
|
|
3166
|
+
action: z9.enum([
|
|
3369
3167
|
"assigned",
|
|
3370
3168
|
"mentioned",
|
|
3371
3169
|
"build_failed",
|
|
@@ -3376,15 +3174,15 @@ Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
|
3376
3174
|
"merge_train_removed",
|
|
3377
3175
|
"review_requested"
|
|
3378
3176
|
]).optional().describe("Filter by action type"),
|
|
3379
|
-
author_id:
|
|
3380
|
-
project_id:
|
|
3381
|
-
group_id:
|
|
3382
|
-
state:
|
|
3383
|
-
type:
|
|
3384
|
-
first:
|
|
3385
|
-
after:
|
|
3386
|
-
last:
|
|
3387
|
-
before:
|
|
3177
|
+
author_id: z9.number().optional().describe("Filter by author ID"),
|
|
3178
|
+
project_id: z9.string().optional().describe("Filter by project ID or path"),
|
|
3179
|
+
group_id: z9.string().optional().describe("Filter by group ID"),
|
|
3180
|
+
state: z9.enum(["pending", "done"]).optional().describe("Filter by state (default: pending)"),
|
|
3181
|
+
type: z9.enum(["Issue", "MergeRequest", "DesignManagement::Design", "Alert", "Epic", "Commit"]).optional().describe("Filter by target type"),
|
|
3182
|
+
first: z9.number().optional().describe("Number of items to return from the beginning (default: 20, max: 100)"),
|
|
3183
|
+
after: z9.string().optional().describe("Cursor for forward pagination - use endCursor from previous response"),
|
|
3184
|
+
last: z9.number().optional().describe("Number of items to return from the end (for backward pagination)"),
|
|
3185
|
+
before: z9.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
|
|
3388
3186
|
},
|
|
3389
3187
|
execute: async (args, _ctx) => {
|
|
3390
3188
|
const client = getGitLabClient();
|
|
@@ -3403,11 +3201,11 @@ Use 'before' with the 'startCursor' from pageInfo to get the previous page.`,
|
|
|
3403
3201
|
return JSON.stringify(result, null, 2);
|
|
3404
3202
|
}
|
|
3405
3203
|
}),
|
|
3406
|
-
gitlab_mark_todo_done:
|
|
3204
|
+
gitlab_mark_todo_done: tool9({
|
|
3407
3205
|
description: `Mark a specific TODO item as done.
|
|
3408
3206
|
Use this to mark a single TODO as completed.`,
|
|
3409
3207
|
args: {
|
|
3410
|
-
todo_id:
|
|
3208
|
+
todo_id: z9.number().describe("The ID of the TODO item to mark as done")
|
|
3411
3209
|
},
|
|
3412
3210
|
execute: async (args, _ctx) => {
|
|
3413
3211
|
const client = getGitLabClient();
|
|
@@ -3415,7 +3213,7 @@ Use this to mark a single TODO as completed.`,
|
|
|
3415
3213
|
return JSON.stringify(result, null, 2);
|
|
3416
3214
|
}
|
|
3417
3215
|
}),
|
|
3418
|
-
gitlab_mark_all_todos_done:
|
|
3216
|
+
gitlab_mark_all_todos_done: tool9({
|
|
3419
3217
|
description: `Mark all TODO items as done.
|
|
3420
3218
|
Use this to mark all pending TODOs for the current user as completed.`,
|
|
3421
3219
|
args: {},
|
|
@@ -3425,7 +3223,7 @@ Use this to mark all pending TODOs for the current user as completed.`,
|
|
|
3425
3223
|
return JSON.stringify(result, null, 2);
|
|
3426
3224
|
}
|
|
3427
3225
|
}),
|
|
3428
|
-
gitlab_get_todo_count:
|
|
3226
|
+
gitlab_get_todo_count: tool9({
|
|
3429
3227
|
description: `Get the count of pending TODO items.
|
|
3430
3228
|
Returns the total number of pending TODOs for the current user.`,
|
|
3431
3229
|
args: {},
|
|
@@ -3438,15 +3236,15 @@ Returns the total number of pending TODOs for the current user.`,
|
|
|
3438
3236
|
};
|
|
3439
3237
|
|
|
3440
3238
|
// src/tools/wikis.ts
|
|
3441
|
-
import { tool as
|
|
3442
|
-
var
|
|
3239
|
+
import { tool as tool10 } from "@opencode-ai/plugin";
|
|
3240
|
+
var z10 = tool10.schema;
|
|
3443
3241
|
var wikiTools = {
|
|
3444
|
-
gitlab_get_wiki_page:
|
|
3242
|
+
gitlab_get_wiki_page: tool10({
|
|
3445
3243
|
description: `Get a wiki page with its content.
|
|
3446
3244
|
Returns the wiki page content and metadata.`,
|
|
3447
3245
|
args: {
|
|
3448
|
-
project_id:
|
|
3449
|
-
slug:
|
|
3246
|
+
project_id: z10.string().describe("The project ID or URL-encoded path"),
|
|
3247
|
+
slug: z10.string().describe("The slug (URL-friendly name) of the wiki page")
|
|
3450
3248
|
},
|
|
3451
3249
|
execute: async (args, _ctx) => {
|
|
3452
3250
|
const client = getGitLabClient();
|
|
@@ -3457,15 +3255,15 @@ Returns the wiki page content and metadata.`,
|
|
|
3457
3255
|
};
|
|
3458
3256
|
|
|
3459
3257
|
// src/tools/work-items.ts
|
|
3460
|
-
import { tool as
|
|
3461
|
-
var
|
|
3258
|
+
import { tool as tool11 } from "@opencode-ai/plugin";
|
|
3259
|
+
var z11 = tool11.schema;
|
|
3462
3260
|
var workItemTools = {
|
|
3463
|
-
gitlab_get_work_item:
|
|
3261
|
+
gitlab_get_work_item: tool11({
|
|
3464
3262
|
description: `Get a single work item (issue, epic, task, etc.).
|
|
3465
3263
|
Work items are the new unified model for issues, epics, tasks, and other work tracking items in GitLab.`,
|
|
3466
3264
|
args: {
|
|
3467
|
-
project_id:
|
|
3468
|
-
work_item_id:
|
|
3265
|
+
project_id: z11.string().describe("The project ID or URL-encoded path"),
|
|
3266
|
+
work_item_id: z11.number().describe("The ID of the work item")
|
|
3469
3267
|
},
|
|
3470
3268
|
execute: async (args, _ctx) => {
|
|
3471
3269
|
const client = getGitLabClient();
|
|
@@ -3473,17 +3271,17 @@ Work items are the new unified model for issues, epics, tasks, and other work tr
|
|
|
3473
3271
|
return JSON.stringify(workItem, null, 2);
|
|
3474
3272
|
}
|
|
3475
3273
|
}),
|
|
3476
|
-
gitlab_list_work_items:
|
|
3274
|
+
gitlab_list_work_items: tool11({
|
|
3477
3275
|
description: `List work items in a project or group.
|
|
3478
3276
|
Work items include issues, epics, tasks, and other work tracking items.`,
|
|
3479
3277
|
args: {
|
|
3480
|
-
project_id:
|
|
3481
|
-
group_id:
|
|
3482
|
-
state:
|
|
3483
|
-
search:
|
|
3484
|
-
labels:
|
|
3485
|
-
work_item_type:
|
|
3486
|
-
limit:
|
|
3278
|
+
project_id: z11.string().optional().describe("The project ID or URL-encoded path"),
|
|
3279
|
+
group_id: z11.string().optional().describe("The group ID or URL-encoded path"),
|
|
3280
|
+
state: z11.enum(["opened", "closed", "all"]).optional().describe("Filter by state (default: opened)"),
|
|
3281
|
+
search: z11.string().optional().describe("Search work items by title or description"),
|
|
3282
|
+
labels: z11.string().optional().describe("Comma-separated list of labels to filter by"),
|
|
3283
|
+
work_item_type: z11.string().optional().describe("Filter by work item type (e.g., 'Issue', 'Epic', 'Task')"),
|
|
3284
|
+
limit: z11.number().optional().describe("Maximum number of results (default: 20)")
|
|
3487
3285
|
},
|
|
3488
3286
|
execute: async (args, _ctx) => {
|
|
3489
3287
|
const client = getGitLabClient();
|
|
@@ -3499,12 +3297,12 @@ Work items include issues, epics, tasks, and other work tracking items.`,
|
|
|
3499
3297
|
return JSON.stringify(workItems, null, 2);
|
|
3500
3298
|
}
|
|
3501
3299
|
}),
|
|
3502
|
-
gitlab_get_work_item_notes:
|
|
3300
|
+
gitlab_get_work_item_notes: tool11({
|
|
3503
3301
|
description: `Get all comments for a work item.
|
|
3504
3302
|
Returns all notes/comments on the work item in chronological order.`,
|
|
3505
3303
|
args: {
|
|
3506
|
-
project_id:
|
|
3507
|
-
work_item_id:
|
|
3304
|
+
project_id: z11.string().describe("The project ID or URL-encoded path"),
|
|
3305
|
+
work_item_id: z11.number().describe("The ID of the work item")
|
|
3508
3306
|
},
|
|
3509
3307
|
execute: async (args, _ctx) => {
|
|
3510
3308
|
const client = getGitLabClient();
|
|
@@ -3512,16 +3310,16 @@ Returns all notes/comments on the work item in chronological order.`,
|
|
|
3512
3310
|
return JSON.stringify(notes, null, 2);
|
|
3513
3311
|
}
|
|
3514
3312
|
}),
|
|
3515
|
-
gitlab_create_work_item:
|
|
3313
|
+
gitlab_create_work_item: tool11({
|
|
3516
3314
|
description: `Create a new work item (issue, task, etc.).
|
|
3517
3315
|
Work items are the new unified model for issues, epics, tasks, and other work tracking items.`,
|
|
3518
3316
|
args: {
|
|
3519
|
-
project_id:
|
|
3520
|
-
title:
|
|
3521
|
-
work_item_type_id:
|
|
3522
|
-
description:
|
|
3523
|
-
labels:
|
|
3524
|
-
assignee_ids:
|
|
3317
|
+
project_id: z11.string().describe("The project ID or URL-encoded path"),
|
|
3318
|
+
title: z11.string().describe("The title of the work item"),
|
|
3319
|
+
work_item_type_id: z11.number().describe("The ID of the work item type (e.g., 1 for Issue, 2 for Task)"),
|
|
3320
|
+
description: z11.string().optional().describe("The description of the work item (supports Markdown)"),
|
|
3321
|
+
labels: z11.array(z11.string()).optional().describe("Array of label names"),
|
|
3322
|
+
assignee_ids: z11.array(z11.number()).optional().describe("Array of user IDs to assign")
|
|
3525
3323
|
},
|
|
3526
3324
|
execute: async (args, _ctx) => {
|
|
3527
3325
|
const client = getGitLabClient();
|
|
@@ -3535,17 +3333,17 @@ Work items are the new unified model for issues, epics, tasks, and other work tr
|
|
|
3535
3333
|
return JSON.stringify(workItem, null, 2);
|
|
3536
3334
|
}
|
|
3537
3335
|
}),
|
|
3538
|
-
gitlab_update_work_item:
|
|
3336
|
+
gitlab_update_work_item: tool11({
|
|
3539
3337
|
description: `Update an existing work item.
|
|
3540
3338
|
Can update title, description, state, labels, and assignees.`,
|
|
3541
3339
|
args: {
|
|
3542
|
-
project_id:
|
|
3543
|
-
work_item_id:
|
|
3544
|
-
title:
|
|
3545
|
-
description:
|
|
3546
|
-
state_event:
|
|
3547
|
-
labels:
|
|
3548
|
-
assignee_ids:
|
|
3340
|
+
project_id: z11.string().describe("The project ID or URL-encoded path"),
|
|
3341
|
+
work_item_id: z11.number().describe("The ID of the work item"),
|
|
3342
|
+
title: z11.string().optional().describe("The new title"),
|
|
3343
|
+
description: z11.string().optional().describe("The new description (supports Markdown)"),
|
|
3344
|
+
state_event: z11.enum(["close", "reopen"]).optional().describe("Change the state (close or reopen)"),
|
|
3345
|
+
labels: z11.array(z11.string()).optional().describe("Array of label names"),
|
|
3346
|
+
assignee_ids: z11.array(z11.number()).optional().describe("Array of user IDs to assign")
|
|
3549
3347
|
},
|
|
3550
3348
|
execute: async (args, _ctx) => {
|
|
3551
3349
|
const client = getGitLabClient();
|
|
@@ -3559,12 +3357,12 @@ Can update title, description, state, labels, and assignees.`,
|
|
|
3559
3357
|
return JSON.stringify(workItem, null, 2);
|
|
3560
3358
|
}
|
|
3561
3359
|
}),
|
|
3562
|
-
gitlab_create_work_item_note:
|
|
3360
|
+
gitlab_create_work_item_note: tool11({
|
|
3563
3361
|
description: `Create a comment on a work item.`,
|
|
3564
3362
|
args: {
|
|
3565
|
-
project_id:
|
|
3566
|
-
work_item_id:
|
|
3567
|
-
body:
|
|
3363
|
+
project_id: z11.string().describe("The project ID or URL-encoded path"),
|
|
3364
|
+
work_item_id: z11.number().describe("The ID of the work item"),
|
|
3365
|
+
body: z11.string().describe("The content of the note/comment (supports Markdown)")
|
|
3568
3366
|
},
|
|
3569
3367
|
execute: async (args, _ctx) => {
|
|
3570
3368
|
const client = getGitLabClient();
|
|
@@ -3575,17 +3373,17 @@ Can update title, description, state, labels, and assignees.`,
|
|
|
3575
3373
|
};
|
|
3576
3374
|
|
|
3577
3375
|
// src/tools/discussions-unified.ts
|
|
3578
|
-
import { tool as
|
|
3579
|
-
var
|
|
3580
|
-
var positionSchema =
|
|
3581
|
-
base_sha:
|
|
3582
|
-
start_sha:
|
|
3583
|
-
head_sha:
|
|
3584
|
-
position_type:
|
|
3585
|
-
old_path:
|
|
3586
|
-
new_path:
|
|
3587
|
-
old_line:
|
|
3588
|
-
new_line:
|
|
3376
|
+
import { tool as tool12 } from "@opencode-ai/plugin";
|
|
3377
|
+
var z12 = tool12.schema;
|
|
3378
|
+
var positionSchema = z12.object({
|
|
3379
|
+
base_sha: z12.string().describe("SHA of the base commit"),
|
|
3380
|
+
start_sha: z12.string().describe("SHA of the start commit"),
|
|
3381
|
+
head_sha: z12.string().describe("SHA of the head commit"),
|
|
3382
|
+
position_type: z12.enum(["text", "image"]).describe("Type of position"),
|
|
3383
|
+
old_path: z12.string().optional().describe("Path of the file before changes"),
|
|
3384
|
+
new_path: z12.string().optional().describe("Path of the file after changes"),
|
|
3385
|
+
old_line: z12.number().optional().describe("Line number in the old version"),
|
|
3386
|
+
new_line: z12.number().optional().describe("Line number in the new version")
|
|
3589
3387
|
});
|
|
3590
3388
|
function validateResourceParams(resourceType, args) {
|
|
3591
3389
|
switch (resourceType) {
|
|
@@ -3612,7 +3410,7 @@ var discussionsUnifiedTools = {
|
|
|
3612
3410
|
/**
|
|
3613
3411
|
* List discussions for any GitLab resource type
|
|
3614
3412
|
*/
|
|
3615
|
-
gitlab_list_discussions:
|
|
3413
|
+
gitlab_list_discussions: tool12({
|
|
3616
3414
|
description: `List discussions (comment threads) on any GitLab resource.
|
|
3617
3415
|
Supports: merge_requests, issues, epics, commits, snippets.
|
|
3618
3416
|
|
|
@@ -3628,17 +3426,17 @@ Examples:
|
|
|
3628
3426
|
- Commit: resource_type="commit", project_id="group/project", sha="abc123"
|
|
3629
3427
|
- Snippet: resource_type="snippet", project_id="group/project", snippet_id=789`,
|
|
3630
3428
|
args: {
|
|
3631
|
-
resource_type:
|
|
3632
|
-
project_id:
|
|
3633
|
-
group_id:
|
|
3634
|
-
iid:
|
|
3635
|
-
sha:
|
|
3636
|
-
snippet_id:
|
|
3429
|
+
resource_type: z12.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
|
|
3430
|
+
project_id: z12.string().optional().describe("Project ID or path. Required for merge_request, issue, commit, snippet"),
|
|
3431
|
+
group_id: z12.string().optional().describe("Group ID or path. Required for epic"),
|
|
3432
|
+
iid: z12.number().optional().describe("Internal ID of the resource (for merge_request, issue, epic)"),
|
|
3433
|
+
sha: z12.string().optional().describe("Commit SHA (required for commit)"),
|
|
3434
|
+
snippet_id: z12.number().optional().describe("Snippet ID (required for snippet)"),
|
|
3637
3435
|
// Pagination
|
|
3638
|
-
first:
|
|
3639
|
-
after:
|
|
3640
|
-
before:
|
|
3641
|
-
last:
|
|
3436
|
+
first: z12.number().optional().describe("Number of items to return (default: 20)"),
|
|
3437
|
+
after: z12.string().optional().describe("Cursor for pagination - use endCursor from previous response"),
|
|
3438
|
+
before: z12.string().optional().describe("Cursor for backward pagination"),
|
|
3439
|
+
last: z12.number().optional().describe("Number of items from the end")
|
|
3642
3440
|
},
|
|
3643
3441
|
execute: async (args, _ctx) => {
|
|
3644
3442
|
validateResourceParams(args.resource_type, args);
|
|
@@ -3692,7 +3490,7 @@ Examples:
|
|
|
3692
3490
|
/**
|
|
3693
3491
|
* Get a specific discussion thread from any GitLab resource
|
|
3694
3492
|
*/
|
|
3695
|
-
gitlab_get_discussion:
|
|
3493
|
+
gitlab_get_discussion: tool12({
|
|
3696
3494
|
description: `Get a specific discussion thread with all its replies.
|
|
3697
3495
|
Returns the discussion with its 'notes' array containing all comments.
|
|
3698
3496
|
|
|
@@ -3705,13 +3503,13 @@ Required parameters vary by resource type:
|
|
|
3705
3503
|
- commit: project_id, sha, discussion_id
|
|
3706
3504
|
- snippet: project_id, snippet_id, discussion_id`,
|
|
3707
3505
|
args: {
|
|
3708
|
-
resource_type:
|
|
3709
|
-
discussion_id:
|
|
3710
|
-
project_id:
|
|
3711
|
-
group_id:
|
|
3712
|
-
iid:
|
|
3713
|
-
sha:
|
|
3714
|
-
snippet_id:
|
|
3506
|
+
resource_type: z12.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
|
|
3507
|
+
discussion_id: z12.string().describe("The ID of the discussion thread"),
|
|
3508
|
+
project_id: z12.string().optional().describe("Project ID or path"),
|
|
3509
|
+
group_id: z12.string().optional().describe("Group ID or path (for epic)"),
|
|
3510
|
+
iid: z12.number().optional().describe("Internal ID (for merge_request, issue, epic)"),
|
|
3511
|
+
sha: z12.string().optional().describe("Commit SHA (for commit)"),
|
|
3512
|
+
snippet_id: z12.number().optional().describe("Snippet ID (for snippet)")
|
|
3715
3513
|
},
|
|
3716
3514
|
execute: async (args, _ctx) => {
|
|
3717
3515
|
validateResourceParams(args.resource_type, args);
|
|
@@ -3759,7 +3557,7 @@ Required parameters vary by resource type:
|
|
|
3759
3557
|
/**
|
|
3760
3558
|
* Create a new discussion thread or reply to an existing one
|
|
3761
3559
|
*/
|
|
3762
|
-
gitlab_create_discussion:
|
|
3560
|
+
gitlab_create_discussion: tool12({
|
|
3763
3561
|
description: `Create a new discussion thread or reply to an existing one.
|
|
3764
3562
|
|
|
3765
3563
|
For NEW discussion: Omit discussion_id
|
|
@@ -3772,14 +3570,14 @@ Examples:
|
|
|
3772
3570
|
- Reply to thread: resource_type="merge_request", ..., discussion_id="...", body="..."
|
|
3773
3571
|
- Code comment: resource_type="merge_request", ..., body="...", position={base_sha, head_sha, ...}`,
|
|
3774
3572
|
args: {
|
|
3775
|
-
resource_type:
|
|
3776
|
-
body:
|
|
3777
|
-
project_id:
|
|
3778
|
-
group_id:
|
|
3779
|
-
iid:
|
|
3780
|
-
sha:
|
|
3781
|
-
snippet_id:
|
|
3782
|
-
discussion_id:
|
|
3573
|
+
resource_type: z12.enum(["merge_request", "issue", "epic", "commit", "snippet"]).describe("Type of GitLab resource"),
|
|
3574
|
+
body: z12.string().describe("The comment text (Markdown supported)"),
|
|
3575
|
+
project_id: z12.string().optional().describe("Project ID or path"),
|
|
3576
|
+
group_id: z12.string().optional().describe("Group ID or path (for epic)"),
|
|
3577
|
+
iid: z12.number().optional().describe("Internal ID (for merge_request, issue, epic)"),
|
|
3578
|
+
sha: z12.string().optional().describe("Commit SHA (for commit)"),
|
|
3579
|
+
snippet_id: z12.number().optional().describe("Snippet ID (for snippet)"),
|
|
3580
|
+
discussion_id: z12.string().optional().describe("If provided, replies to existing discussion. If omitted, creates new thread"),
|
|
3783
3581
|
position: positionSchema.optional().describe("Position for code-specific comments (MR/commit only)")
|
|
3784
3582
|
},
|
|
3785
3583
|
execute: async (args, _ctx) => {
|
|
@@ -3844,17 +3642,17 @@ Examples:
|
|
|
3844
3642
|
/**
|
|
3845
3643
|
* Resolve or unresolve a discussion thread
|
|
3846
3644
|
*/
|
|
3847
|
-
gitlab_resolve_discussion:
|
|
3645
|
+
gitlab_resolve_discussion: tool12({
|
|
3848
3646
|
description: `Mark a discussion thread as resolved or unresolve it.
|
|
3849
3647
|
Only works for resolvable discussions (MRs and issues only).
|
|
3850
3648
|
|
|
3851
3649
|
Use after addressing feedback to indicate the discussion is complete.`,
|
|
3852
3650
|
args: {
|
|
3853
|
-
resource_type:
|
|
3854
|
-
action:
|
|
3855
|
-
discussion_id:
|
|
3856
|
-
project_id:
|
|
3857
|
-
iid:
|
|
3651
|
+
resource_type: z12.enum(["merge_request", "issue"]).describe("Type of resource (only MR and issue discussions can be resolved)"),
|
|
3652
|
+
action: z12.enum(["resolve", "unresolve"]).describe("Whether to resolve or unresolve"),
|
|
3653
|
+
discussion_id: z12.string().describe("The ID of the discussion thread"),
|
|
3654
|
+
project_id: z12.string().describe("Project ID or path"),
|
|
3655
|
+
iid: z12.number().describe("Internal ID of the MR or issue")
|
|
3858
3656
|
},
|
|
3859
3657
|
execute: async (args, _ctx) => {
|
|
3860
3658
|
const client = getGitLabClient();
|
|
@@ -3893,6 +3691,224 @@ Use after addressing feedback to indicate the discussion is complete.`,
|
|
|
3893
3691
|
})
|
|
3894
3692
|
};
|
|
3895
3693
|
|
|
3694
|
+
// src/tools/notes-unified.ts
|
|
3695
|
+
import { tool as tool13 } from "@opencode-ai/plugin";
|
|
3696
|
+
var z13 = tool13.schema;
|
|
3697
|
+
var VALID_LIST_CREATE_TYPES = ["merge_request", "issue", "epic", "snippet"];
|
|
3698
|
+
var VALID_GET_NOTE_TYPES = ["issue", "epic"];
|
|
3699
|
+
function validationError2(param, resourceType) {
|
|
3700
|
+
return new Error(
|
|
3701
|
+
`Missing required parameter: '${param}' is required for resource_type '${resourceType}'`
|
|
3702
|
+
);
|
|
3703
|
+
}
|
|
3704
|
+
function validateListCreateParams(resourceType, args) {
|
|
3705
|
+
if (!VALID_LIST_CREATE_TYPES.includes(resourceType)) {
|
|
3706
|
+
throw new Error(
|
|
3707
|
+
`Invalid resource_type '${resourceType}'. Must be one of: ${VALID_LIST_CREATE_TYPES.join(", ")}`
|
|
3708
|
+
);
|
|
3709
|
+
}
|
|
3710
|
+
switch (resourceType) {
|
|
3711
|
+
case "merge_request":
|
|
3712
|
+
case "issue":
|
|
3713
|
+
if (!args.project_id) throw validationError2("project_id", resourceType);
|
|
3714
|
+
if (args.iid == null) throw validationError2("iid", resourceType);
|
|
3715
|
+
break;
|
|
3716
|
+
case "epic":
|
|
3717
|
+
if (!args.group_id) throw validationError2("group_id", resourceType);
|
|
3718
|
+
if (args.iid == null) throw validationError2("iid", resourceType);
|
|
3719
|
+
break;
|
|
3720
|
+
case "snippet":
|
|
3721
|
+
if (!args.project_id) throw validationError2("project_id", resourceType);
|
|
3722
|
+
if (args.snippet_id == null) throw validationError2("snippet_id", resourceType);
|
|
3723
|
+
break;
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
function validateGetNoteParams(resourceType, args) {
|
|
3727
|
+
if (!VALID_GET_NOTE_TYPES.includes(resourceType)) {
|
|
3728
|
+
throw new Error(
|
|
3729
|
+
`Invalid resource_type '${resourceType}'. Must be one of: ${VALID_GET_NOTE_TYPES.join(", ")}`
|
|
3730
|
+
);
|
|
3731
|
+
}
|
|
3732
|
+
if (args.note_id == null) throw validationError2("note_id", resourceType);
|
|
3733
|
+
switch (resourceType) {
|
|
3734
|
+
case "issue":
|
|
3735
|
+
if (!args.project_id) throw validationError2("project_id", resourceType);
|
|
3736
|
+
if (args.iid == null) throw validationError2("iid", resourceType);
|
|
3737
|
+
break;
|
|
3738
|
+
case "epic":
|
|
3739
|
+
if (!args.group_id) throw validationError2("group_id", resourceType);
|
|
3740
|
+
if (args.iid == null) throw validationError2("iid", resourceType);
|
|
3741
|
+
break;
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3744
|
+
var notesUnifiedTools = {
|
|
3745
|
+
/**
|
|
3746
|
+
* List notes/comments for any GitLab resource type
|
|
3747
|
+
*/
|
|
3748
|
+
gitlab_list_notes: tool13({
|
|
3749
|
+
description: `List all notes/comments on any GitLab resource using GraphQL API with pagination support.
|
|
3750
|
+
Returns all comments including system notes in chronological order.
|
|
3751
|
+
This is easier to read than discussions which have nested structure.
|
|
3752
|
+
|
|
3753
|
+
The response includes pagination information (pageInfo) with cursors for fetching additional pages.
|
|
3754
|
+
Use 'after' with the 'endCursor' from pageInfo to get the next page.
|
|
3755
|
+
Use 'before' with the 'startCursor' from pageInfo to get the previous page.
|
|
3756
|
+
|
|
3757
|
+
Examples:
|
|
3758
|
+
- MR: resource_type="merge_request", project_id="group/project", iid=123
|
|
3759
|
+
- Issue: resource_type="issue", project_id="group/project", iid=456
|
|
3760
|
+
- Epic: resource_type="epic", group_id="my-group", iid=1
|
|
3761
|
+
- Snippet: resource_type="snippet", project_id="group/project", snippet_id=789`,
|
|
3762
|
+
args: {
|
|
3763
|
+
resource_type: z13.enum(["merge_request", "issue", "epic", "snippet"]).describe("Type of GitLab resource"),
|
|
3764
|
+
project_id: z13.string().optional().describe("Project ID or path. Required for merge_request, issue, snippet"),
|
|
3765
|
+
group_id: z13.string().optional().describe("Group ID or path. Required for epic"),
|
|
3766
|
+
iid: z13.number().optional().describe("Internal ID of the resource (for merge_request, issue, epic)"),
|
|
3767
|
+
snippet_id: z13.number().optional().describe("Snippet ID (required for snippet)"),
|
|
3768
|
+
// Pagination
|
|
3769
|
+
first: z13.number().optional().describe("Number of items to return from the beginning (default: 20, max: 100)"),
|
|
3770
|
+
after: z13.string().optional().describe("Cursor for forward pagination - use endCursor from previous response"),
|
|
3771
|
+
last: z13.number().optional().describe("Number of items to return from the end (for backward pagination)"),
|
|
3772
|
+
before: z13.string().optional().describe("Cursor for backward pagination - use startCursor from previous response")
|
|
3773
|
+
},
|
|
3774
|
+
execute: async (args, _ctx) => {
|
|
3775
|
+
validateListCreateParams(args.resource_type, args);
|
|
3776
|
+
const client = getGitLabClient();
|
|
3777
|
+
const paginationOptions = {
|
|
3778
|
+
first: args.first,
|
|
3779
|
+
after: args.after,
|
|
3780
|
+
last: args.last,
|
|
3781
|
+
before: args.before
|
|
3782
|
+
};
|
|
3783
|
+
switch (args.resource_type) {
|
|
3784
|
+
case "merge_request":
|
|
3785
|
+
return JSON.stringify(
|
|
3786
|
+
await client.listMrNotes(args.project_id, args.iid, paginationOptions),
|
|
3787
|
+
null,
|
|
3788
|
+
2
|
|
3789
|
+
);
|
|
3790
|
+
case "issue":
|
|
3791
|
+
return JSON.stringify(
|
|
3792
|
+
await client.listIssueNotes(args.project_id, args.iid, paginationOptions),
|
|
3793
|
+
null,
|
|
3794
|
+
2
|
|
3795
|
+
);
|
|
3796
|
+
case "epic":
|
|
3797
|
+
return JSON.stringify(
|
|
3798
|
+
await client.listEpicNotes(args.group_id, args.iid, paginationOptions),
|
|
3799
|
+
null,
|
|
3800
|
+
2
|
|
3801
|
+
);
|
|
3802
|
+
case "snippet":
|
|
3803
|
+
return JSON.stringify(
|
|
3804
|
+
await client.listSnippetNotes(args.project_id, args.snippet_id, paginationOptions),
|
|
3805
|
+
null,
|
|
3806
|
+
2
|
|
3807
|
+
);
|
|
3808
|
+
default:
|
|
3809
|
+
throw new Error(`Unsupported resource type: ${args.resource_type}`);
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
}),
|
|
3813
|
+
/**
|
|
3814
|
+
* Get a single note/comment by its ID
|
|
3815
|
+
*/
|
|
3816
|
+
gitlab_get_note: tool13({
|
|
3817
|
+
description: `Get a single note/comment from an issue or epic by its ID.
|
|
3818
|
+
Returns the full details of a specific note including author, body, timestamps, and metadata.
|
|
3819
|
+
Useful when you need to retrieve a specific comment without fetching all notes.
|
|
3820
|
+
|
|
3821
|
+
Supports: issues, epics (MR notes use discussions API)
|
|
3822
|
+
|
|
3823
|
+
Examples:
|
|
3824
|
+
- Issue note: resource_type="issue", project_id="group/project", iid=456, note_id=123
|
|
3825
|
+
- Epic note: resource_type="epic", group_id="my-group", iid=1, note_id=456`,
|
|
3826
|
+
args: {
|
|
3827
|
+
resource_type: z13.enum(["issue", "epic"]).describe("Type of GitLab resource (issue or epic only)"),
|
|
3828
|
+
note_id: z13.number().describe("The ID of the note to retrieve"),
|
|
3829
|
+
project_id: z13.string().optional().describe("Project ID or path. Required for issue"),
|
|
3830
|
+
group_id: z13.string().optional().describe("Group ID or path. Required for epic"),
|
|
3831
|
+
iid: z13.number().describe("Internal ID of the issue or epic")
|
|
3832
|
+
},
|
|
3833
|
+
execute: async (args, _ctx) => {
|
|
3834
|
+
validateGetNoteParams(args.resource_type, args);
|
|
3835
|
+
const client = getGitLabClient();
|
|
3836
|
+
switch (args.resource_type) {
|
|
3837
|
+
case "issue":
|
|
3838
|
+
return JSON.stringify(
|
|
3839
|
+
await client.getIssueNote(args.project_id, args.iid, args.note_id),
|
|
3840
|
+
null,
|
|
3841
|
+
2
|
|
3842
|
+
);
|
|
3843
|
+
case "epic":
|
|
3844
|
+
return JSON.stringify(
|
|
3845
|
+
await client.getEpicNote(args.group_id, args.iid, args.note_id),
|
|
3846
|
+
null,
|
|
3847
|
+
2
|
|
3848
|
+
);
|
|
3849
|
+
default:
|
|
3850
|
+
throw new Error(`Unsupported resource type: ${args.resource_type}`);
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
}),
|
|
3854
|
+
/**
|
|
3855
|
+
* Create a simple note/comment on any GitLab resource
|
|
3856
|
+
*/
|
|
3857
|
+
gitlab_create_note: tool13({
|
|
3858
|
+
description: `Add a simple comment/note to any GitLab resource.
|
|
3859
|
+
Creates a standalone comment (not part of a thread).
|
|
3860
|
+
|
|
3861
|
+
For replying to existing discussion threads, use gitlab_create_discussion
|
|
3862
|
+
with discussion_id parameter instead.
|
|
3863
|
+
|
|
3864
|
+
Examples:
|
|
3865
|
+
- MR comment: resource_type="merge_request", project_id="group/project", iid=123, body="LGTM!"
|
|
3866
|
+
- Issue comment: resource_type="issue", project_id="group/project", iid=456, body="Working on this"
|
|
3867
|
+
- Epic comment: resource_type="epic", group_id="my-group", iid=1, body="Planning complete"
|
|
3868
|
+
- Snippet comment: resource_type="snippet", project_id="group/project", snippet_id=789, body="Nice code!"`,
|
|
3869
|
+
args: {
|
|
3870
|
+
resource_type: z13.enum(["merge_request", "issue", "epic", "snippet"]).describe("Type of GitLab resource"),
|
|
3871
|
+
body: z13.string().describe("The content of the note/comment (supports Markdown)"),
|
|
3872
|
+
project_id: z13.string().optional().describe("Project ID or path. Required for merge_request, issue, snippet"),
|
|
3873
|
+
group_id: z13.string().optional().describe("Group ID or path. Required for epic"),
|
|
3874
|
+
iid: z13.number().optional().describe("Internal ID of the resource (for merge_request, issue, epic)"),
|
|
3875
|
+
snippet_id: z13.number().optional().describe("Snippet ID (required for snippet)")
|
|
3876
|
+
},
|
|
3877
|
+
execute: async (args, _ctx) => {
|
|
3878
|
+
validateListCreateParams(args.resource_type, args);
|
|
3879
|
+
const client = getGitLabClient();
|
|
3880
|
+
switch (args.resource_type) {
|
|
3881
|
+
case "merge_request":
|
|
3882
|
+
return JSON.stringify(
|
|
3883
|
+
await client.createMrNote(args.project_id, args.iid, args.body),
|
|
3884
|
+
null,
|
|
3885
|
+
2
|
|
3886
|
+
);
|
|
3887
|
+
case "issue":
|
|
3888
|
+
return JSON.stringify(
|
|
3889
|
+
await client.createIssueNote(args.project_id, args.iid, args.body),
|
|
3890
|
+
null,
|
|
3891
|
+
2
|
|
3892
|
+
);
|
|
3893
|
+
case "epic":
|
|
3894
|
+
return JSON.stringify(
|
|
3895
|
+
await client.createEpicNote(args.group_id, args.iid, args.body),
|
|
3896
|
+
null,
|
|
3897
|
+
2
|
|
3898
|
+
);
|
|
3899
|
+
case "snippet":
|
|
3900
|
+
return JSON.stringify(
|
|
3901
|
+
await client.createSnippetNote(args.project_id, args.snippet_id, args.body),
|
|
3902
|
+
null,
|
|
3903
|
+
2
|
|
3904
|
+
);
|
|
3905
|
+
default:
|
|
3906
|
+
throw new Error(`Unsupported resource type: ${args.resource_type}`);
|
|
3907
|
+
}
|
|
3908
|
+
}
|
|
3909
|
+
})
|
|
3910
|
+
};
|
|
3911
|
+
|
|
3896
3912
|
// src/tools/git.ts
|
|
3897
3913
|
import { tool as tool14 } from "@opencode-ai/plugin";
|
|
3898
3914
|
|
|
@@ -4249,8 +4265,6 @@ var gitlabPlugin = async (_input) => {
|
|
|
4249
4265
|
...userTools,
|
|
4250
4266
|
// Security Tools
|
|
4251
4267
|
...securityTools,
|
|
4252
|
-
// Snippet Tools
|
|
4253
|
-
...snippetTools,
|
|
4254
4268
|
// TODO Tools
|
|
4255
4269
|
...todoTools,
|
|
4256
4270
|
// Wiki Tools
|
|
@@ -4259,6 +4273,8 @@ var gitlabPlugin = async (_input) => {
|
|
|
4259
4273
|
...workItemTools,
|
|
4260
4274
|
// Unified Discussion Tools (covers MR, issue, epic, commit, snippet discussions)
|
|
4261
4275
|
...discussionsUnifiedTools,
|
|
4276
|
+
// Unified Notes Tools (covers MR, issue, epic, snippet notes)
|
|
4277
|
+
...notesUnifiedTools,
|
|
4262
4278
|
// Git Tools
|
|
4263
4279
|
...gitTools,
|
|
4264
4280
|
// Audit Tools
|