import{existsSync as L}from"fs";import{fileURLToPath as R}from"url";import{dirname as O,resolve as N}from"path";var j=Object.freeze({SENTRY:"sentry",JIRA:"jira",GITHUB:"github",GITLAB:"gitlab",SLACK:"slack",LARK:"lark",OPENAI_BILLING:"openai_billing",ANTHROPIC_BILLING:"anthropic_billing",CURSOR_ADMIN:"cursor_admin",NOTION:"notion",GOOGLE:"google",PLANE:"plane",LINEAR:"linear",FIGMA:"figma",HUBSPOT:"hubspot",OPEN_DESIGN:"open_design",LINKEDIN_PERSONAL:"linkedin_personal",LINKEDIN_BUSINESS:"linkedin_business",DISCORD:"discord"}),k=Object.freeze({sentry:{id:"sentry",name:"Sentry",connectPath:"/integrations?provider=sentry"},jira:{id:"jira",name:"Jira",connectPath:"/integrations?provider=jira"},github:{id:"github",name:"GitHub",connectPath:"/integrations?provider=github"},gitlab:{id:"gitlab",name:"GitLab",connectPath:"/integrations?provider=gitlab"},slack:{id:"slack",name:"Slack",connectPath:"/integrations?provider=slack"},lark:{id:"lark",name:"Lark",connectPath:"/integrations?provider=lark"},openai_billing:{id:"openai_billing",name:"OpenAI Admin",connectPath:"/integrations?provider=openai_billing"},anthropic_billing:{id:"anthropic_billing",name:"Anthropic Admin",connectPath:"/integrations?provider=anthropic_billing"},cursor_admin:{id:"cursor_admin",name:"Cursor Admin",connectPath:"/integrations?provider=cursor_admin"},notion:{id:"notion",name:"Notion",connectPath:"/integrations?provider=notion"},google:{id:"google",name:"Google Docs",connectPath:"/integrations?provider=google"},plane:{id:"plane",name:"Plane",connectPath:"/integrations?provider=plane"},linear:{id:"linear",name:"Linear",connectPath:"/integrations?provider=linear"},figma:{id:"figma",name:"Figma",connectPath:"/integrations?provider=figma"},hubspot:{id:"hubspot",name:"HubSpot",connectPath:"/integrations?provider=hubspot"},open_design:{id:"open_design",name:"OpenDesign",connectPath:"/integrations?provider=open_design"},linkedin_personal:{id:"linkedin_personal",name:"LinkedIn (Personal)",connectPath:"/integrations?provider=linkedin_personal"},linkedin_business:{id:"linkedin_business",name:"LinkedIn (Business)",connectPath:"/integrations?provider=linkedin_business"},discord:{id:"discord",name:"Discord",connectPath:"/integrations?provider=discord"}});function v(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let u=O(R(import.meta.url)),i=N(u,"..","bin","mcp-skill.mjs");return L(i)?i:null}function P(){let u=process.env.GITLAB_API_URL;if(u)return u.replace(/\/+$/,"");let i=(process.env.GITLAB_URL||process.env.GITLAB_INSTANCE_URL||"https://gitlab.com").trim().replace(/\/+$/,"");return/\/api\/v\d+$/.test(i)?i:`${i}/api/v4`}function T(){if(process.env.GITLAB_OAUTH_TOKEN)return{Authorization:`Bearer ${process.env.GITLAB_OAUTH_TOKEN}`};let u=process.env.GITLAB_TOKEN;if(!u)throw new Error("GitLab is not connected: set GITLAB_TOKEN (personal/project access token, api scope) or GITLAB_OAUTH_TOKEN.");return{"PRIVATE-TOKEN":u}}async function h(u,i={}){let t=/^https?:\/\//.test(u)?u:`${P()}${u}`,n={Accept:"application/json","User-Agent":"Zibby-App",...T(),...i.body?{"Content-Type":"application/json"}:{}},e=await fetch(t,{method:i.method||"GET",headers:n,body:i.body?JSON.stringify(i.body):void 0});if(!e.ok){let s=await e.text().catch(()=>"");throw new Error(`GitLab API ${e.status}: ${s.slice(0,300)}`)}return i.raw?e.text():e.json()}function I(){let u=process.env.GITLAB_API_URL;return(process.env.GITLAB_URL||process.env.GITLAB_INSTANCE_URL||(u?u.replace(/\/api\/v\d+\/?$/,""):"")||"https://gitlab.com").trim().replace(/\/+$/,"").replace(/\/api\/v\d+$/,"")}function q(){return process.env.GITLAB_OAUTH_TOKEN||process.env.GITLAB_TOKEN||null}function m(u){let i=String(u);return/^\d+$/.test(i)?i:encodeURIComponent(i)}var J={id:"gitlab",serverName:"gitlab",allowedTools:["mcp__gitlab__*"],requiresIntegration:j.GITLAB,envKeys:["GITLAB_TOKEN","GITLAB_OAUTH_TOKEN","GITLAB_INSTANCE_URL","GITLAB_API_URL"],description:"GitLab \u2014 merge requests, diffs, MR reviews/discussions, issues",promptFragment:`## GitLab (connected)
You have access to the user's GitLab projects via the REST API (cloud gitlab.com OR self-hosted). A "merge request" (MR) is GitLab's pull request. An MR is addressed by a PROJECT (numeric id OR full path like "group/repo") and an \`iid\` (the per-project MR number shown in the URL). For projects, prefer the full path form ("group/subgroup/repo") \u2014 it's what users have. Available tools:

### Discovery
- gitlab_list_projects: List the projects this token can access (the ones you're a member of), optionally filtered by a search query. Use to find a RELATED project worth cloning for cross-repo context.
- gitlab_clone: Clone a project locally (shallow, auto-authenticated) to read code OUTSIDE the MR diff \u2014 callers, shared types, an existing util, or a cross-repo dependency. After cloning, use Grep/Glob/Read on the returned path. Clone SPARINGLY (only when correctness needs context beyond the diff).

### Merge requests
- gitlab_create_mr: OPEN a merge request (POST /projects/{id}/merge_requests). The source_branch must already be pushed. Returns the REAL pr_url (the MR's web_url) from GitLab \u2014 never fabricate it. Expected business errors (no changes between branches, an MR already exists, source==target) come back as { success:false, skippedReason } \u2014 not a hard failure.
- gitlab_accept_mr: ACCEPT (merge) an MR (PUT /projects/{id}/merge_requests/{iid}/merge). Optional squash, mergeCommitMessage, mergeWhenPipelineSucceeds. Returns { success:true, merged:true, sha (merge_commit_sha) } on a real merge. Expected non-mergeable cases (405/406 = not mergeable / WIP / conflicts / pipeline not done, 404) come back as { success:false, skippedReason } \u2014 not a hard failure.
- gitlab_get_mr: Get an MR's details (title, description, author, source/target branch, state, web url, diff_refs)
- gitlab_get_mr_changes: Get the MR's changed files with per-file diffs \u2014 THIS is the code to review
- gitlab_list_mrs: List a project's merge requests (filter by state: opened|closed|merged|all)
- gitlab_list_mr_notes: Get the discussion/notes thread on an MR
- gitlab_get_discussion: Read a single MR discussion (thread) by id \u2014 all its notes + the file/line it is anchored to
- gitlab_reply_discussion: Reply IN-THREAD to an existing MR discussion (conversational reply, not a new review)
- gitlab_post_mr_note: Post a general (non-inline) comment on an MR
- gitlab_post_mr_discussion: Post an INLINE review comment anchored to a file + line in the MR diff. Needs diff_refs (pass them from gitlab_get_mr / gitlab_get_mr_changes, or omit and the tool fetches them). Provide newLine for added/changed lines (or oldLine for removed/context lines).

### Issues
- gitlab_get_issue: Get a single issue (by project + issue iid) \u2014 title, description, state, labels, assignee, web url
- gitlab_list_issues: List a project's issues (filter by state: opened|closed|all, labels, updatedAfter cursor)
- gitlab_add_issue_comment: Add a comment to an issue (also the way to record an MR link on a ticket)

### Notes
- A code-review flow is: gitlab_get_mr (context + diff_refs) \u2192 gitlab_get_mr_changes (the diff) \u2192 gitlab_post_mr_discussion per inline finding \u2192 gitlab_post_mr_note for the summary.
- If an inline position is rejected by GitLab (bad line anchor), fall back to gitlab_post_mr_note with the file/line in the text.`,resolve(){let u=v();if(!u)return{command:null,args:[],env:{},description:this.description};let i={};for(let t of this.envKeys)process.env[t]&&(i[t]=process.env[t]);return{type:"stdio",command:"node",args:[u,"../dist/gitlab.js","gitlabSkill"],env:i,description:this.description,alwaysLoad:!0}},async handleToolCall(u,i){try{switch(u){case"gitlab_clone":{let{projectPath:t,projectId:n,destination:e,branch:s}=i||{},r=t&&String(t).trim();if(!r&&n!=null&&(/^\d+$/.test(String(n))?r=(await h(`/projects/${m(n)}`))?.path_with_namespace:r=String(n).trim()),!r)return JSON.stringify({error:'projectPath (e.g. "group/repo") or a numeric projectId is required'});let c=q();if(!c)return JSON.stringify({error:"GitLab is not connected (no token to authenticate the clone)."});let{execSync:a}=await import("child_process"),{join:p,resolve:l}=await import("path"),{existsSync:g,mkdirSync:o}=await import("fs"),_=e?l(e):l(process.cwd(),".zibby","repos"),b=r.split("/").filter(Boolean).pop(),d=p(_,b);if(o(_,{recursive:!0}),g(d))return JSON.stringify({success:!0,path:d,message:`Already cloned at ${d}`,alreadyCloned:!0});let y=I().replace(/^https?:\/\//,""),w=`${I().startsWith("http://")?"http":"https"}://oauth2:${c}@${y}/${r}.git`,S=s?`--branch "${String(s).replace(/"/g,"")}" `:"";try{a(`git clone --depth 1 ${S}${w} "${d}"`,{stdio:"pipe",env:{...process.env,GIT_TERMINAL_PROMPT:"0"}});let f=a(`ls -la "${d}"`,{encoding:"utf-8"});return JSON.stringify({success:!0,path:d,message:`Cloned ${r} to ${d}`,contents:f.split(`
`).slice(0,30).join(`
`)})}catch(f){let A=String(f.message||f).split(c).join("***");return JSON.stringify({error:`Clone failed: ${A}`})}}case"gitlab_create_mr":{let t=i?.project??i?.projectId,n=i?.source_branch??i?.sourceBranch,{title:e}=i||{};if(!t||!n||!e)return JSON.stringify({error:'project (id or "group/repo" path), source_branch, and title are required'});let s=m(t),r=i?.target_branch??i?.targetBranch;if(!r)try{r=(await h(`/projects/${s}`)).default_branch||"main"}catch{r="main"}let c={source_branch:String(n),target_branch:String(r),title:String(e),description:i?.description?String(i.description):""};try{let a=await h(`/projects/${s}/merge_requests`,{method:"POST",body:c});return JSON.stringify({success:!0,pr_url:a.web_url,number:a.iid,branch:c.source_branch,targetBranch:c.target_branch,project:String(t),provider:"gitlab",state:a.state})}catch(a){let p=String(a.message||a);if(/GitLab API (409|400)/.test(p))return JSON.stringify({success:!1,branch:c.source_branch,targetBranch:c.target_branch,project:String(t),provider:"gitlab",skippedReason:p});throw a}}case"gitlab_accept_mr":{let t=i?.project??i?.projectId,{iid:n}=i||{};if(!t||!n)return JSON.stringify({error:'project (id or "group/repo" path) and iid are required'});let e=m(t),s={};i.squash!=null&&(s.squash=!!i.squash),i.mergeCommitMessage&&(s.merge_commit_message=String(i.mergeCommitMessage)),i.mergeWhenPipelineSucceeds!=null&&(s.merge_when_pipeline_succeeds=!!i.mergeWhenPipelineSucceeds);try{let r=await h(`/projects/${e}/merge_requests/${n}/merge`,{method:"PUT",body:s});return JSON.stringify({success:!0,merged:!0,sha:r.merge_commit_sha??r.sha??null,iid:r.iid??n,project:String(t),provider:"gitlab",state:r.state})}catch(r){let c=String(r.message||r);if(/GitLab API (405|406|404)/.test(c))return JSON.stringify({success:!1,iid:n,project:String(t),provider:"gitlab",skippedReason:c});throw r}}case"gitlab_get_mr":{let{projectId:t,iid:n}=i||{};if(!t||!n)return JSON.stringify({error:"projectId and iid are required"});let e=await h(`/projects/${m(t)}/merge_requests/${n}`);return JSON.stringify({iid:e.iid,projectId:e.project_id,title:e.title,description:(e.description||"").slice(0,5e3),state:e.state,author:e.author?.username,sourceBranch:e.source_branch,targetBranch:e.target_branch,draft:e.draft??e.work_in_progress??!1,mergeStatus:e.merge_status,changesCount:e.changes_count,labels:Array.isArray(e.labels)?e.labels:[],webUrl:e.web_url,createdAt:e.created_at,updatedAt:e.updated_at,mergedAt:e.merged_at,diffRefs:e.diff_refs||null})}case"gitlab_get_mr_changes":{let{projectId:t,iid:n}=i||{};if(!t||!n)return JSON.stringify({error:"projectId and iid are required"});let e=await h(`/projects/${m(t)}/merge_requests/${n}/changes`),s=Array.isArray(e.changes)?e.changes:[];return JSON.stringify({iid:e.iid,total:s.length,diffRefs:e.diff_refs||null,files:s.map(r=>({oldPath:r.old_path,newPath:r.new_path,newFile:!!r.new_file,deletedFile:!!r.deleted_file,renamedFile:!!r.renamed_file,diff:typeof r.diff=="string"?r.diff.slice(0,3e3):""}))})}case"gitlab_list_mrs":{let{projectId:t,state:n,targetBranch:e,sourceBranch:s,authorUsername:r,labels:c,search:a,sort:p,orderBy:l,limit:g}=i||{};if(!t)return JSON.stringify({error:"projectId is required"});let o=new URLSearchParams;o.set("state",n||"opened"),o.set("per_page",String(g||20)),o.set("order_by",l||"updated_at"),o.set("sort",p||"desc"),e&&o.set("target_branch",e),s&&o.set("source_branch",s),r&&o.set("author_username",r),c&&o.set("labels",Array.isArray(c)?c.join(","):c),a&&o.set("search",a);let _=await h(`/projects/${m(t)}/merge_requests?${o.toString()}`),b=(Array.isArray(_)?_:[]).map(d=>({iid:d.iid,title:d.title,state:d.state,author:d.author?.username,sourceBranch:d.source_branch,targetBranch:d.target_branch,draft:d.draft??d.work_in_progress??!1,labels:Array.isArray(d.labels)?d.labels:[],webUrl:d.web_url,createdAt:d.created_at,updatedAt:d.updated_at}));return JSON.stringify({count:b.length,mergeRequests:b})}case"gitlab_list_mr_notes":{let{projectId:t,iid:n,limit:e}=i||{};if(!t||!n)return JSON.stringify({error:"projectId and iid are required"});let s=await h(`/projects/${m(t)}/merge_requests/${n}/notes?per_page=${e||50}&sort=asc&order_by=created_at`);return JSON.stringify({total:Array.isArray(s)?s.length:0,notes:(Array.isArray(s)?s:[]).map(r=>({id:r.id,author:r.author?.username,body:(r.body||"").slice(0,1e3),system:!!r.system,createdAt:r.created_at}))})}case"gitlab_post_mr_note":{let{projectId:t,iid:n,body:e}=i||{};if(!t||!n||!e)return JSON.stringify({error:"projectId, iid, and body are required"});let s=await h(`/projects/${m(t)}/merge_requests/${n}/notes`,{method:"POST",body:{body:String(e)}});return JSON.stringify({ok:!0,id:s.id,createdAt:s.created_at})}case"gitlab_post_mr_discussion":{let{projectId:t,iid:n,path:e,oldPath:s,newLine:r,oldLine:c,body:a}=i||{};if(!t||!n||!e||!a)return JSON.stringify({error:"projectId, iid, path, and body are required"});if(r==null&&c==null)return JSON.stringify({error:"newLine (added/changed line) or oldLine (removed/context line) is required to anchor an inline comment"});let p=m(t),l=i.diffRefs||null;if(l||(l=(await h(`/projects/${p}/merge_requests/${n}`)).diff_refs||null),!l||!l.head_sha)return JSON.stringify({error:"could not resolve diff_refs for this MR \u2014 cannot anchor an inline comment. Use gitlab_post_mr_note instead."});let g={base_sha:l.base_sha,start_sha:l.start_sha,head_sha:l.head_sha,position_type:"text",new_path:e,old_path:s||e};r!=null&&(g.new_line=Number(r)),c!=null&&(g.old_line=Number(c));try{let o=await h(`/projects/${p}/merge_requests/${n}/discussions`,{method:"POST",body:{body:String(a),position:g}});return JSON.stringify({ok:!0,discussionId:o.id})}catch(o){return JSON.stringify({ok:!1,error:`inline anchor rejected (${o.message}). The line must be part of the MR diff. Fall back to gitlab_post_mr_note with the file/line in the text.`})}}case"gitlab_create_mr_review":{let{projectId:t,iid:n,body:e,comments:s}=i||{};if(!t||!n)return JSON.stringify({error:"projectId and iid are required"});let r=m(t),c=Array.isArray(s)?s.filter(o=>o&&o.path&&o.body&&(o.newLine!=null||o.oldLine!=null)):[];if(!e&&c.length===0)return JSON.stringify({error:"a review needs a body and/or inline comments"});let a=i.diffRefs||null;c.length>0&&!a&&(a=(await h(`/projects/${r}/merge_requests/${n}`)).diff_refs||null);let p=!1;e&&(await h(`/projects/${r}/merge_requests/${n}/notes`,{method:"POST",body:{body:String(e)}}),p=!0);let l=0,g=[];if(c.length>0&&a)for(let o of c){let _={base_sha:a.base_sha,start_sha:a.start_sha,head_sha:a.head_sha,position_type:"text",new_path:o.path,old_path:o.oldPath||o.path};o.newLine!=null&&(_.new_line=Number(o.newLine)),o.oldLine!=null&&(_.old_line=Number(o.oldLine));try{await h(`/projects/${r}/merge_requests/${n}/discussions`,{method:"POST",body:{body:String(o.body),position:_}}),l+=1}catch(b){g.push(`${o.path}:${o.newLine??o.oldLine} \u2014 ${b.message}`)}}else c.length>0&&!a&&g.push("no diff_refs available \u2014 inline comments skipped (pass diffRefs from gitlab_get_mr)");return JSON.stringify({ok:!0,notePosted:p,inlinePosted:l,inlineErrors:g.length?g:void 0})}case"gitlab_get_discussion":{let{projectId:t,iid:n,discussionId:e}=i||{};if(!t||!n||!e)return JSON.stringify({error:"projectId, iid, and discussionId are required"});let s=await h(`/projects/${m(t)}/merge_requests/${n}/discussions/${encodeURIComponent(e)}`),r=Array.isArray(s.notes)?s.notes:[],c=r.find(p=>p.position)||null,a=c?c.position:null;return JSON.stringify({discussionId:s.id,individualNote:!!s.individual_note,path:a&&(a.new_path||a.old_path)||null,newLine:a?a.new_line??null:null,oldLine:a?a.old_line??null:null,diffRefs:a?{base_sha:a.base_sha,start_sha:a.start_sha,head_sha:a.head_sha}:null,notes:r.map(p=>({id:p.id,author:p.author?.username,body:(p.body||"").slice(0,4e3),system:!!p.system,createdAt:p.created_at}))})}case"gitlab_reply_discussion":{let{projectId:t,iid:n,discussionId:e,body:s}=i||{};if(!t||!n||!e||!s)return JSON.stringify({error:"projectId, iid, discussionId, and body are required"});let r=await h(`/projects/${m(t)}/merge_requests/${n}/discussions/${encodeURIComponent(e)}/notes`,{method:"POST",body:{body:String(s)}});return JSON.stringify({ok:!0,id:r.id,createdAt:r.created_at})}case"gitlab_list_projects":{let{query:t,limit:n}=i||{},e=Math.min(Number(n)>0?Number(n):50,200),s=new URLSearchParams;s.set("membership","true"),s.set("simple","true"),s.set("order_by","last_activity_at"),s.set("sort","desc"),s.set("per_page",String(Math.min(e+1,100))),t&&s.set("search",String(t));let r=await h(`/projects?${s.toString()}`),c=Array.isArray(r)?r:[],a=c.length>e,p=c.slice(0,e).map(l=>({fullPath:l.path_with_namespace,name:l.name,webUrl:l.web_url,defaultBranch:l.default_branch||null,visibility:l.visibility||null}));return JSON.stringify({count:p.length,truncated:a,projects:p})}case"gitlab_list_issues":{let{projectId:t,state:n,labels:e,assigneeUsername:s,authorUsername:r,updatedAfter:c,search:a,sort:p,orderBy:l,limit:g}=i||{};if(!t)return JSON.stringify({error:"projectId is required"});let o=new URLSearchParams;o.set("state",n||"opened"),o.set("per_page",String(g||30)),o.set("order_by",l||"updated_at"),o.set("sort",p||"desc"),e&&o.set("labels",Array.isArray(e)?e.join(","):e),s&&o.set("assignee_username",s),r&&o.set("author_username",r),c&&o.set("updated_after",c),a&&o.set("search",a);let _=await h(`/projects/${m(t)}/issues?${o.toString()}`),b=(Array.isArray(_)?_:[]).map(d=>({iid:d.iid,title:d.title,state:d.state,labels:Array.isArray(d.labels)?d.labels:[],author:d.author?.username,assignees:(d.assignees||[]).map(y=>y.username),userNotesCount:d.user_notes_count,webUrl:d.web_url,createdAt:d.created_at,updatedAt:d.updated_at}));return JSON.stringify({count:b.length,issues:b})}case"gitlab_get_issue":{let{projectId:t,iid:n}=i||{};if(!t||!n)return JSON.stringify({error:"projectId and iid are required"});let e=await h(`/projects/${m(t)}/issues/${n}`);return JSON.stringify({iid:e.iid,projectId:e.project_id,title:e.title,description:(e.description||"").slice(0,5e3),state:e.state,labels:Array.isArray(e.labels)?e.labels:[],author:e.author?.username,assignees:(e.assignees||[]).map(s=>s.username),milestone:e.milestone?.title||null,webUrl:e.web_url,createdAt:e.created_at,updatedAt:e.updated_at,closedAt:e.closed_at})}case"gitlab_add_issue_comment":{let{projectId:t,iid:n,body:e}=i||{};if(!t||!n||!e)return JSON.stringify({error:"projectId, iid, and body are required"});let s=await h(`/projects/${m(t)}/issues/${n}/notes`,{method:"POST",body:{body:String(e)}});return JSON.stringify({ok:!0,id:s.id,createdAt:s.created_at})}default:return JSON.stringify({error:`Unknown tool: ${u}`})}}catch(t){return JSON.stringify({error:t.message})}},tools:[{name:"gitlab_list_projects",description:"List the GitLab projects this token can access (the projects you are a member of), optionally filtered by a search query. Use this to discover a RELATED project worth cloning when a change's correctness depends on another accessible repo. Returns a normalized list of { fullPath, name, webUrl, defaultBranch, visibility } and a truncated flag.",input_schema:{type:"object",properties:{query:{type:"string",description:"Optional search term matched against project name/path"},limit:{type:"number",description:"Max projects (default 50, hard max 200)"}}}},{name:"gitlab_clone",description:"Clone a GitLab repository locally (shallow) so you can read code OUTSIDE the MR diff \u2014 callers of a changed symbol, shared types/contracts, an existing util, or a cross-repo dependency. Auto-authenticates with the connected GitLab token. After cloning, use Grep/Glob/Read on the returned path. Clone SPARINGLY \u2014 only when the change's correctness depends on code beyond the diff.",input_schema:{type:"object",properties:{projectPath:{type:"string",description:'Full project path, e.g. "group/subgroup/repo" (preferred).'},projectId:{type:"string",description:"Alternatively a numeric project id (resolved to its path via the API)."},branch:{type:"string",description:"Branch to clone (default: the repo default branch)."},destination:{type:"string",description:"Destination dir (default: <workspace>/.zibby/repos/<repo>)."}}}},{name:"gitlab_create_mr",description:"Open a merge request on GitLab (POST /projects/{id}/merge_requests). The source_branch must already be pushed. Returns the REAL pr_url (the MR web_url) from GitLab \u2014 never fabricate it. Expected business outcomes (no changes between branches, an MR already exists, source==target) return { success:false, skippedReason } rather than erroring.",input_schema:{type:"object",properties:{project:{type:"string",description:'Project numeric id OR full path (e.g. "group/repo")'},source_branch:{type:"string",description:"Source branch to merge FROM (must already be pushed)"},target_branch:{type:"string",description:"Target branch to merge INTO (default: the project's default branch)"},title:{type:"string",description:"MR title"},description:{type:"string",description:"MR description (markdown)"}},required:["project","source_branch","title"]}},{name:"gitlab_accept_mr",description:"Accept (merge) a merge request on GitLab (PUT /projects/{id}/merge_requests/{iid}/merge). Optional squash, mergeCommitMessage, mergeWhenPipelineSucceeds. Returns { success:true, merged:true, sha } with the REAL merge_commit_sha from GitLab. Expected non-mergeable outcomes (405/406 = not mergeable / WIP / conflicts / pipeline not done, 404 = not found) return { success:false, skippedReason } rather than erroring.",input_schema:{type:"object",properties:{project:{type:"string",description:'Project numeric id OR full path (e.g. "group/repo")'},iid:{type:"number",description:"Merge request iid (the per-project MR number in the URL)"},squash:{type:"boolean",description:"Squash the MR commits into one on merge (optional)"},mergeCommitMessage:{type:"string",description:"Custom merge commit message (optional)"},mergeWhenPipelineSucceeds:{type:"boolean",description:"Merge automatically once the pipeline succeeds (optional)"}},required:["project","iid"]}},{name:"gitlab_get_mr",description:"Get a GitLab merge request \u2014 title, description, branches, state, author, web url, and diff_refs (needed to anchor inline review comments).",input_schema:{type:"object",properties:{projectId:{type:"string",description:'Project numeric id OR full path (e.g. "group/repo")'},iid:{type:"number",description:"Merge request iid (the per-project MR number in the URL)"}},required:["projectId","iid"]}},{name:"gitlab_get_mr_changes",description:"Get the changed files of a GitLab merge request with per-file diffs \u2014 the actual code changes to review. Also returns diff_refs for inline comments.",input_schema:{type:"object",properties:{projectId:{type:"string",description:'Project numeric id OR full path (e.g. "group/repo")'},iid:{type:"number",description:"Merge request iid"}},required:["projectId","iid"]}},{name:"gitlab_list_mrs",description:"List a GitLab project's merge requests, filtered by state and other criteria. Returns newest-updated first.",input_schema:{type:"object",properties:{projectId:{type:"string",description:'Project numeric id OR full path (e.g. "group/repo")'},state:{type:"string",enum:["opened","closed","merged","locked","all"],description:"Filter by state (default: opened)"},targetBranch:{type:"string",description:"Filter by target branch"},sourceBranch:{type:"string",description:"Filter by source branch"},authorUsername:{type:"string",description:"Filter by author username"},labels:{type:"array",items:{type:"string"},description:"Only MRs carrying ALL of these labels"},search:{type:"string",description:"Search title and description"},orderBy:{type:"string",enum:["created_at","updated_at","title"],description:"Sort field (default: updated_at)"},sort:{type:"string",enum:["asc","desc"],description:"Sort direction (default: desc)"},limit:{type:"number",description:"Max MRs (default: 20)"}},required:["projectId"]}},{name:"gitlab_list_mr_notes",description:"List the discussion notes on a GitLab merge request (chronological).",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project numeric id OR full path"},iid:{type:"number",description:"Merge request iid"},limit:{type:"number",description:"Max notes (default 50)"}},required:["projectId","iid"]}},{name:"gitlab_post_mr_note",description:"Post a general (non-inline) comment on a GitLab merge request. Use for a review summary or a top-level remark.",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project numeric id OR full path"},iid:{type:"number",description:"Merge request iid"},body:{type:"string",description:"Comment body (markdown)"}},required:["projectId","iid","body"]}},{name:"gitlab_post_mr_discussion",description:"Post an INLINE review comment anchored to a file + line in a GitLab merge request diff. Provide newLine (added/changed line) or oldLine (removed/context line). Pass diffRefs from gitlab_get_mr/gitlab_get_mr_changes, or omit to have the tool fetch them. If the line anchor is rejected, fall back to gitlab_post_mr_note.",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project numeric id OR full path"},iid:{type:"number",description:"Merge request iid"},path:{type:"string",description:"New file path as it appears in the diff"},oldPath:{type:"string",description:"Old file path (defaults to path)"},newLine:{type:"number",description:"Line number in the NEW version of the file (for added/changed lines)"},oldLine:{type:"number",description:"Line number in the OLD version (for removed/context lines)"},body:{type:"string",description:"The inline comment text (markdown)"},diffRefs:{type:"object",description:"The MR diff_refs ({ base_sha, start_sha, head_sha }) from gitlab_get_mr. Omit and the tool fetches them."}},required:["projectId","iid","path","body"]}},{name:"gitlab_create_mr_review",description:"Post a full review on a GitLab merge request in one call: a summary note plus optional inline comments anchored to file/line in the diff. Convenience wrapper over gitlab_post_mr_note + gitlab_post_mr_discussion.",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project numeric id OR full path"},iid:{type:"number",description:"Merge request iid"},body:{type:"string",description:"The review summary (markdown). Posted as a top-level MR note."},diffRefs:{type:"object",description:"The MR diff_refs ({ base_sha, start_sha, head_sha }) from gitlab_get_mr \u2014 required to anchor inline comments. Omit and the tool fetches them."},comments:{type:"array",description:"Optional inline comments, each anchored to a changed line in a file.",items:{type:"object",properties:{path:{type:"string",description:"New file path as it appears in the diff"},oldPath:{type:"string",description:"Old file path (defaults to path)"},newLine:{type:"number",description:"Line number in the NEW version of the file (for added/changed lines)"},oldLine:{type:"number",description:"Line number in the OLD version (for removed/context lines)"},body:{type:"string",description:"The inline comment text (markdown)"}},required:["path","body"]}}},required:["projectId","iid"]}},{name:"gitlab_get_discussion",description:"Read a single GitLab merge-request DISCUSSION (thread) by its discussion id: all notes in order plus the diff position (file + line) it is anchored to. Use this to understand a human's reply to a previous review discussion before replying in-thread.",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project numeric id OR full path"},iid:{type:"number",description:"Merge request iid"},discussionId:{type:"string",description:"The discussion id (from the Note Hook payload or gitlab_list_mr_notes)"}},required:["projectId","iid","discussionId"]}},{name:"gitlab_reply_discussion",description:"Reply IN-THREAD to an existing GitLab merge-request discussion (a conversational reply appended to the SAME thread \u2014 NOT a fresh review). Use after gitlab_get_discussion to answer a human's reply to a review comment.",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project numeric id OR full path"},iid:{type:"number",description:"Merge request iid"},discussionId:{type:"string",description:"The discussion id to reply to"},body:{type:"string",description:"The reply text (markdown)"}},required:["projectId","iid","discussionId","body"]}},{name:"gitlab_list_issues",description:"List a GitLab project's issues, filtered by state, labels, and an updatedAfter polling cursor. Returns newest-updated first.",input_schema:{type:"object",properties:{projectId:{type:"string",description:'Project numeric id OR full path (e.g. "group/repo")'},state:{type:"string",enum:["opened","closed","all"],description:"Filter by state (default: opened)"},labels:{type:"array",items:{type:"string"},description:"Only issues carrying ALL of these labels"},assigneeUsername:{type:"string",description:"Filter by assignee username"},authorUsername:{type:"string",description:"Filter by author username"},updatedAfter:{type:"string",description:"ISO-8601 timestamp; only issues updated after this (polling cursor)"},search:{type:"string",description:"Search title and description"},orderBy:{type:"string",enum:["created_at","updated_at"],description:"Sort field (default: updated_at)"},sort:{type:"string",enum:["asc","desc"],description:"Sort direction (default: desc)"},limit:{type:"number",description:"Max issues (default: 30)"}},required:["projectId"]}},{name:"gitlab_get_issue",description:"Get a single GitLab issue with full detail (title, description, state, labels, assignees, web url).",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project numeric id OR full path"},iid:{type:"number",description:"Issue iid (the per-project issue number in the URL)"}},required:["projectId","iid"]}},{name:"gitlab_add_issue_comment",description:"Add a comment to a GitLab issue. Also the way to record an MR link on a ticket (post a markdown link).",input_schema:{type:"object",properties:{projectId:{type:"string",description:"Project numeric id OR full path"},iid:{type:"number",description:"Issue iid"},body:{type:"string",description:"Comment body (markdown)"}},required:["projectId","iid","body"]}}]};export{J as gitlabSkill,h as glFetch};
