import{existsSync as O}from"fs";import{fileURLToPath as v}from"url";import{dirname as N,resolve as k}from"path";var S=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"}),q=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"}});import{spawn as U,execSync as M}from"child_process";import{existsSync as C,mkdirSync as J,readdirSync as D,statSync as F,readFileSync as H}from"fs";import{resolve as W,join as z,basename as Y}from"path";function I(l,s,r,n,e="clone"){try{l(`git -C "${s}" remote set-url origin "${r}"`,{stdio:"pipe"})}catch(i){let t=String(i?.message||i);n&&(t=t.split(n).join("***")),console.error(`[${e}] WARNING: failed to strip token from .git/config: ${t}`)}}function T(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let l=N(v(import.meta.url)),s=k(l,"..","bin","mcp-skill.mjs");return O(s)?s:null}function P(){let l=process.env.GITLAB_API_URL;if(l)return l.replace(/\/+$/,"");let s=(process.env.GITLAB_URL||process.env.GITLAB_INSTANCE_URL||"https://gitlab.com").trim().replace(/\/+$/,"");return/\/api\/v\d+$/.test(s)?s:`${s}/api/v4`}function $(){if(process.env.GITLAB_OAUTH_TOKEN)return{Authorization:`Bearer ${process.env.GITLAB_OAUTH_TOKEN}`};let l=process.env.GITLAB_TOKEN;if(!l)throw new Error("GitLab is not connected: set GITLAB_TOKEN (personal/project access token, api scope) or GITLAB_OAUTH_TOKEN.");return{"PRIVATE-TOKEN":l}}async function h(l,s={}){let r=/^https?:\/\//.test(l)?l:`${P()}${l}`,n={Accept:"application/json","User-Agent":"Zibby-App",...$(),...s.body?{"Content-Type":"application/json"}:{}},e=await fetch(r,{method:s.method||"GET",headers:n,body:s.body?JSON.stringify(s.body):void 0});if(!e.ok){let i=await e.text().catch(()=>"");throw new Error(`GitLab API ${e.status}: ${i.slice(0,300)}`)}return s.raw?e.text():e.json()}function A(){let l=process.env.GITLAB_API_URL;return(process.env.GITLAB_URL||process.env.GITLAB_INSTANCE_URL||(l?l.replace(/\/api\/v\d+\/?$/,""):"")||"https://gitlab.com").trim().replace(/\/+$/,"").replace(/\/api\/v\d+$/,"")}function G(){return process.env.GITLAB_OAUTH_TOKEN||process.env.GITLAB_TOKEN||null}function g(l){let s=String(l);return/^\d+$/.test(s)?s:encodeURIComponent(s)}var re={id:"gitlab",serverName:"gitlab",allowedTools:["mcp__gitlab__*"],requiresIntegration:S.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 l=T();if(!l)return{command:null,args:[],env:{},description:this.description};let s={};for(let r of this.envKeys)process.env[r]&&(s[r]=process.env[r]);return{type:"stdio",command:"node",args:[l,"../dist/gitlab.js","gitlabSkill"],env:s,description:this.description,alwaysLoad:!0}},async handleToolCall(l,s){try{switch(l){case"gitlab_clone":{let{projectPath:r,projectId:n,destination:e,branch:i}=s||{},t=r&&String(r).trim();if(!t&&n!=null&&(/^\d+$/.test(String(n))?t=(await h(`/projects/${g(n)}`))?.path_with_namespace:t=String(n).trim()),!t)return JSON.stringify({error:'projectPath (e.g. "group/repo") or a numeric projectId is required'});let c=G();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:u}=await import("path"),{existsSync:m,mkdirSync:o}=await import("fs"),f=e?u(e):u(process.cwd(),".zibby","repos"),_=t.split("/").filter(Boolean).pop(),d=p(f,_);if(o(f,{recursive:!0}),m(d))return JSON.stringify({success:!0,path:d,message:`Already cloned at ${d}`,alreadyCloned:!0});let y=A().replace(/^https?:\/\//,""),w=A().startsWith("http://")?"http":"https",L=`${w}://oauth2:${c}@${y}/${t}.git`,R=i?`--branch "${String(i).replace(/"/g,"")}" `:"";try{a(`git clone --depth 1 ${R}${L} "${d}"`,{stdio:"pipe",env:{...process.env,GIT_TERMINAL_PROMPT:"0"}});let b=`${w}://${y}/${t}.git`;I(a,d,b,c,"gitlab_clone");let j=a(`ls -la "${d}"`,{encoding:"utf-8"});return JSON.stringify({success:!0,path:d,message:`Cloned ${t} to ${d}`,contents:j.split(`
`).slice(0,30).join(`
`)})}catch(b){let j=String(b.message||b).split(c).join("***").replace(/oauth2:[^@]*@/g,"oauth2:***@");return JSON.stringify({error:`Clone failed: ${j}`})}}case"gitlab_create_mr":{let r=s?.project??s?.projectId,n=s?.source_branch??s?.sourceBranch,{title:e}=s||{};if(!r||!n||!e)return JSON.stringify({error:'project (id or "group/repo" path), source_branch, and title are required'});let i=g(r),t=s?.target_branch??s?.targetBranch;if(!t)try{t=(await h(`/projects/${i}`)).default_branch||"main"}catch{t="main"}let c={source_branch:String(n),target_branch:String(t),title:String(e),description:s?.description?String(s.description):""};try{let a=await h(`/projects/${i}/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(r),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(r),provider:"gitlab",skippedReason:p});throw a}}case"gitlab_accept_mr":{let r=s?.project??s?.projectId,{iid:n}=s||{};if(!r||!n)return JSON.stringify({error:'project (id or "group/repo" path) and iid are required'});let e=g(r),i={};s.squash!=null&&(i.squash=!!s.squash),s.mergeCommitMessage&&(i.merge_commit_message=String(s.mergeCommitMessage)),s.mergeWhenPipelineSucceeds!=null&&(i.merge_when_pipeline_succeeds=!!s.mergeWhenPipelineSucceeds);try{let t=await h(`/projects/${e}/merge_requests/${n}/merge`,{method:"PUT",body:i});return JSON.stringify({success:!0,merged:!0,sha:t.merge_commit_sha??t.sha??null,iid:t.iid??n,project:String(r),provider:"gitlab",state:t.state})}catch(t){let c=String(t.message||t);if(/GitLab API (405|406|404)/.test(c))return JSON.stringify({success:!1,iid:n,project:String(r),provider:"gitlab",skippedReason:c});throw t}}case"gitlab_get_mr":{let{projectId:r,iid:n}=s||{};if(!r||!n)return JSON.stringify({error:"projectId and iid are required"});let e=await h(`/projects/${g(r)}/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:r,iid:n}=s||{};if(!r||!n)return JSON.stringify({error:"projectId and iid are required"});let e=await h(`/projects/${g(r)}/merge_requests/${n}/changes`),i=Array.isArray(e.changes)?e.changes:[];return JSON.stringify({iid:e.iid,total:i.length,diffRefs:e.diff_refs||null,files:i.map(t=>({oldPath:t.old_path,newPath:t.new_path,newFile:!!t.new_file,deletedFile:!!t.deleted_file,renamedFile:!!t.renamed_file,diff:typeof t.diff=="string"?t.diff.slice(0,3e3):""}))})}case"gitlab_list_mrs":{let{projectId:r,state:n,targetBranch:e,sourceBranch:i,authorUsername:t,labels:c,search:a,sort:p,orderBy:u,limit:m}=s||{};if(!r)return JSON.stringify({error:"projectId is required"});let o=new URLSearchParams;o.set("state",n||"opened"),o.set("per_page",String(m||20)),o.set("order_by",u||"updated_at"),o.set("sort",p||"desc"),e&&o.set("target_branch",e),i&&o.set("source_branch",i),t&&o.set("author_username",t),c&&o.set("labels",Array.isArray(c)?c.join(","):c),a&&o.set("search",a);let f=await h(`/projects/${g(r)}/merge_requests?${o.toString()}`),_=(Array.isArray(f)?f:[]).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:_.length,mergeRequests:_})}case"gitlab_list_mr_notes":{let{projectId:r,iid:n,limit:e}=s||{};if(!r||!n)return JSON.stringify({error:"projectId and iid are required"});let i=await h(`/projects/${g(r)}/merge_requests/${n}/notes?per_page=${e||50}&sort=asc&order_by=created_at`);return JSON.stringify({total:Array.isArray(i)?i.length:0,notes:(Array.isArray(i)?i:[]).map(t=>({id:t.id,author:t.author?.username,body:(t.body||"").slice(0,1e3),system:!!t.system,createdAt:t.created_at}))})}case"gitlab_post_mr_note":{let{projectId:r,iid:n,body:e}=s||{};if(!r||!n||!e)return JSON.stringify({error:"projectId, iid, and body are required"});let i=await h(`/projects/${g(r)}/merge_requests/${n}/notes`,{method:"POST",body:{body:String(e)}});return JSON.stringify({ok:!0,id:i.id,createdAt:i.created_at})}case"gitlab_post_mr_discussion":{let{projectId:r,iid:n,path:e,oldPath:i,newLine:t,oldLine:c,body:a}=s||{};if(!r||!n||!e||!a)return JSON.stringify({error:"projectId, iid, path, and body are required"});if(t==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=g(r),u=s.diffRefs||null;if(u||(u=(await h(`/projects/${p}/merge_requests/${n}`)).diff_refs||null),!u||!u.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 m={base_sha:u.base_sha,start_sha:u.start_sha,head_sha:u.head_sha,position_type:"text",new_path:e,old_path:i||e};t!=null&&(m.new_line=Number(t)),c!=null&&(m.old_line=Number(c));try{let o=await h(`/projects/${p}/merge_requests/${n}/discussions`,{method:"POST",body:{body:String(a),position:m}});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:r,iid:n,body:e,comments:i}=s||{};if(!r||!n)return JSON.stringify({error:"projectId and iid are required"});let t=g(r),c=Array.isArray(i)?i.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=s.diffRefs||null;c.length>0&&!a&&(a=(await h(`/projects/${t}/merge_requests/${n}`)).diff_refs||null);let p=!1;e&&(await h(`/projects/${t}/merge_requests/${n}/notes`,{method:"POST",body:{body:String(e)}}),p=!0);let u=0,m=[];if(c.length>0&&a)for(let o of c){let f={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&&(f.new_line=Number(o.newLine)),o.oldLine!=null&&(f.old_line=Number(o.oldLine));try{await h(`/projects/${t}/merge_requests/${n}/discussions`,{method:"POST",body:{body:String(o.body),position:f}}),u+=1}catch(_){m.push(`${o.path}:${o.newLine??o.oldLine} \u2014 ${_.message}`)}}else c.length>0&&!a&&m.push("no diff_refs available \u2014 inline comments skipped (pass diffRefs from gitlab_get_mr)");return JSON.stringify({ok:!0,notePosted:p,inlinePosted:u,inlineErrors:m.length?m:void 0})}case"gitlab_get_discussion":{let{projectId:r,iid:n,discussionId:e}=s||{};if(!r||!n||!e)return JSON.stringify({error:"projectId, iid, and discussionId are required"});let i=await h(`/projects/${g(r)}/merge_requests/${n}/discussions/${encodeURIComponent(e)}`),t=Array.isArray(i.notes)?i.notes:[],c=t.find(p=>p.position)||null,a=c?c.position:null;return JSON.stringify({discussionId:i.id,individualNote:!!i.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:t.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:r,iid:n,discussionId:e,body:i}=s||{};if(!r||!n||!e||!i)return JSON.stringify({error:"projectId, iid, discussionId, and body are required"});let t=await h(`/projects/${g(r)}/merge_requests/${n}/discussions/${encodeURIComponent(e)}/notes`,{method:"POST",body:{body:String(i)}});return JSON.stringify({ok:!0,id:t.id,createdAt:t.created_at})}case"gitlab_list_projects":{let{query:r,limit:n}=s||{},e=Math.min(Number(n)>0?Number(n):50,200),i=new URLSearchParams;i.set("membership","true"),i.set("simple","true"),i.set("order_by","last_activity_at"),i.set("sort","desc"),i.set("per_page",String(Math.min(e+1,100))),r&&i.set("search",String(r));let t=await h(`/projects?${i.toString()}`),c=Array.isArray(t)?t:[],a=c.length>e,p=c.slice(0,e).map(u=>({fullPath:u.path_with_namespace,name:u.name,webUrl:u.web_url,defaultBranch:u.default_branch||null,visibility:u.visibility||null}));return JSON.stringify({count:p.length,truncated:a,projects:p})}case"gitlab_list_issues":{let{projectId:r,state:n,labels:e,assigneeUsername:i,authorUsername:t,updatedAfter:c,search:a,sort:p,orderBy:u,limit:m}=s||{};if(!r)return JSON.stringify({error:"projectId is required"});let o=new URLSearchParams;o.set("state",n||"opened"),o.set("per_page",String(m||30)),o.set("order_by",u||"updated_at"),o.set("sort",p||"desc"),e&&o.set("labels",Array.isArray(e)?e.join(","):e),i&&o.set("assignee_username",i),t&&o.set("author_username",t),c&&o.set("updated_after",c),a&&o.set("search",a);let f=await h(`/projects/${g(r)}/issues?${o.toString()}`),_=(Array.isArray(f)?f:[]).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:_.length,issues:_})}case"gitlab_get_issue":{let{projectId:r,iid:n}=s||{};if(!r||!n)return JSON.stringify({error:"projectId and iid are required"});let e=await h(`/projects/${g(r)}/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(i=>i.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:r,iid:n,body:e}=s||{};if(!r||!n||!e)return JSON.stringify({error:"projectId, iid, and body are required"});let i=await h(`/projects/${g(r)}/issues/${n}/notes`,{method:"POST",body:{body:String(e)}});return JSON.stringify({ok:!0,id:i.id,createdAt:i.created_at})}default:return JSON.stringify({error:`Unknown tool: ${l}`})}}catch(r){return JSON.stringify({error:r.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{re as gitlabSkill,h as glFetch};
