bitbucket-copilot-pr-review 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -0
- package/dist/cli.js +52 -0
- package/package.json +50 -0
- package/schemas/copilot-code-review.schema.json +118 -0
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Bitbucket Copilot PR Review
|
|
2
|
+
|
|
3
|
+
CLI-first pull request review automation for Bitbucket Data Center, powered by the GitHub Copilot SDK.
|
|
4
|
+
|
|
5
|
+
This project computes a PR diff locally, gives Copilot a tightly scoped read-only view of the changed code, and publishes the result back to Bitbucket as Code Insights reports, annotations, and one tagged summary comment.
|
|
6
|
+
|
|
7
|
+
## Highlights
|
|
8
|
+
|
|
9
|
+
- reviews only the changed pull request scope
|
|
10
|
+
- runs from your CI workspace instead of shipping repository contents to a separate service
|
|
11
|
+
- publishes native Bitbucket review artifacts
|
|
12
|
+
- supports single-PR and batch repository review flows
|
|
13
|
+
- loads trusted repo-level configuration from the PR base commit
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- Node.js 24.12+
|
|
18
|
+
- pnpm 10+
|
|
19
|
+
- Bitbucket Data Center API access
|
|
20
|
+
- a GitHub Copilot-enabled account for CI
|
|
21
|
+
|
|
22
|
+
## Use With npx
|
|
23
|
+
|
|
24
|
+
Once published to npm, you can run the CLI directly with `npx`:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
export BITBUCKET_TOKEN="<bitbucket token>"
|
|
28
|
+
export REPO_ROOT="/path/to/local/my-repo"
|
|
29
|
+
|
|
30
|
+
NODE_USE_SYSTEM_CA=1 npx bitbucket-copilot-pr-review review \
|
|
31
|
+
https://bitbucket.example.com/projects/PROJ/repos/my-repo/pull-requests/123 \
|
|
32
|
+
--dry-run
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
When the dry run looks correct, rerun without `--dry-run` to publish the Bitbucket review artifacts.
|
|
36
|
+
|
|
37
|
+
Batch mode works the same way with the published CLI:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
export BITBUCKET_TOKEN="<bitbucket token>"
|
|
41
|
+
|
|
42
|
+
NODE_USE_SYSTEM_CA=1 npx bitbucket-copilot-pr-review batch \
|
|
43
|
+
https://bitbucket.example.com/projects/PROJ/repos/my-repo \
|
|
44
|
+
--dry-run \
|
|
45
|
+
--max-parallel 2
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Quick Start From Source
|
|
49
|
+
|
|
50
|
+
1. Install dependencies and build the CLI locally:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
corepack enable
|
|
54
|
+
pnpm install
|
|
55
|
+
pnpm build
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
2. Export Bitbucket auth and, when needed, point the reviewer at a local checkout:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
export BITBUCKET_TOKEN="<bitbucket token>"
|
|
62
|
+
export REPO_ROOT="/path/to/local/my-repo"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
3. Dry-run one pull request first:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pnpm review:dry-run -- https://bitbucket.example.com/projects/PROJ/repos/my-repo/pull-requests/123
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
4. Publish once the output looks correct:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pnpm review -- https://bitbucket.example.com/projects/PROJ/repos/my-repo/pull-requests/123
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Use `pnpm review --help` or `pnpm batch --help` for command-specific help while developing locally.
|
|
78
|
+
|
|
79
|
+
## How It Works
|
|
80
|
+
|
|
81
|
+
- reads pull request metadata from Bitbucket Data Center
|
|
82
|
+
- computes the effective PR diff from local git data
|
|
83
|
+
- asks Copilot to inspect only the changed review scope through read-only tools
|
|
84
|
+
- validates findings against changed lines before publication
|
|
85
|
+
- publishes a Bitbucket Code Insights report, annotations, and a tagged PR comment
|
|
86
|
+
|
|
87
|
+
## CLI Usage
|
|
88
|
+
|
|
89
|
+
Published package:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
NODE_USE_SYSTEM_CA=1 npx bitbucket-copilot-pr-review review --help
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
NODE_USE_SYSTEM_CA=1 npx bitbucket-copilot-pr-review batch --help
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Local source checkout:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pnpm build
|
|
103
|
+
node dist/cli.js review --help
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Documentation
|
|
107
|
+
|
|
108
|
+
- `docs/operations.md` - configuration, local testing, batch mode, Jenkins usage, release verification, and npm publishing
|
|
109
|
+
- `schemas/copilot-code-review.schema.json` - JSON schema for trusted repo config
|
|
110
|
+
- `Jenkinsfile.example` - sample Jenkins pipeline wiring
|
|
111
|
+
|
|
112
|
+
## Why This Exists
|
|
113
|
+
|
|
114
|
+
Bitbucket Data Center teams often want Copilot-assisted review inside their existing CI and review workflows. This project keeps the review loop inside your own Bitbucket and CI environment while staying conservative about file access, changed-line validation, and publication behavior.
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{createRequire as e}from"node:module";import t from"node:process";import{execFile as n,spawn as r}from"node:child_process";import{mkdir as i,mkdtemp as a,readFile as o,rm as s,rmdir as c,stat as l}from"node:fs/promises";import u from"node:http";import d from"node:https";import{createHash as f}from"node:crypto";import{z as p}from"zod";import{promisify as m}from"node:util";import{tmpdir as h}from"node:os";import g,{dirname as _,join as v}from"node:path";import{accessSync as ee,constants as te,existsSync as y}from"node:fs";import{Socket as b}from"node:net";import{fileURLToPath as ne}from"node:url";import{createInterface as re}from"node:readline/promises";import{deflateRawSync as ie,inflateRawSync as x}from"node:zlib";import ae from"pino";var S=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),C=e(import.meta.url);function w(e){let t={};for(let[n,r]of Object.entries(e))r!==void 0&&(t[n]=r);return t}var T=class extends Error{statusCode;statusMessage;method;url;responseBody;constructor(e,t,n,r,i){super(`Bitbucket request failed: ${n} ${r} -> ${e} ${t}\n${i}`),this.name=`BitbucketApiError`,this.statusCode=e,this.statusMessage=t,this.method=n,this.url=r,this.responseBody=i}},oe=class{caCertPromise;config;constructor(e){this.config=e}buildUrl(e){return new URL(e,`${this.config.baseUrl}/`).toString()}buildHeaders(e){let t=new Headers({Accept:`application/json;charset=UTF-8`});if(e&&t.set(`Content-Type`,`application/json`),this.config.auth.type===`bearer`)t.set(`Authorization`,`Bearer ${this.config.auth.token}`);else{let e=Buffer.from(`${this.config.auth.username}:${this.config.auth.password}`,`utf8`).toString(`base64`);t.set(`Authorization`,`Basic ${e}`)}return t}async loadCaCertificate(){return this.caCertPromise||=this.config.tls.caCertPath?o(this.config.tls.caCertPath,`utf8`):Promise.resolve(void 0),this.caCertPromise}toHeaderRecord(e){let t={};return e.forEach((e,n)=>{t[n]=e}),t}formatNetworkError(e,t,n){let r=n instanceof Error?n:Error(String(n)),i=r,a=i.cause instanceof Error?i.cause:void 0,o=i.code??a?.code,s=a?.message??r.message,c=[`Bitbucket network request failed: ${e} ${t}`,s];return o&&[`CERT_HAS_EXPIRED`,`DEPTH_ZERO_SELF_SIGNED_CERT`,`ERR_TLS_CERT_ALTNAME_INVALID`,`SELF_SIGNED_CERT_IN_CHAIN`,`UNABLE_TO_GET_ISSUER_CERT_LOCALLY`,`UNABLE_TO_VERIFY_LEAF_SIGNATURE`].includes(o)&&c.push(`Hint: this looks like a TLS certificate trust problem. Set BITBUCKET_CA_CERT_PATH to your corporate CA PEM file, or set BITBUCKET_INSECURE_TLS=0 to require strict TLS verification once trust is configured.`),(o===`ECONNREFUSED`||o===`ENOTFOUND`||o===`EHOSTUNREACH`)&&c.push(`Hint: verify the Bitbucket URL you passed to the CLI, VPN connectivity, and whether the Bitbucket host is reachable from this machine.`),c.join(`
|
|
3
|
+
`)}async sendRequest(e,t,n,r){let i=e.protocol===`https:`?d:u,a=e.protocol===`https:`?await this.loadCaCertificate():void 0,o=w({method:t,protocol:e.protocol,hostname:e.hostname,port:e.port?Number.parseInt(e.port,10):void 0,path:`${e.pathname}${e.search}`,headers:n,rejectUnauthorized:e.protocol===`https:`?!this.config.tls.insecureSkipVerify:void 0,ca:a});return new Promise((t,n)=>{let a=i.request(o,e=>{let n=[];e.on(`data`,e=>{n.push(Buffer.isBuffer(e)?e:Buffer.from(e))}),e.on(`end`,()=>{t({statusCode:e.statusCode??0,statusMessage:e.statusMessage??``,body:Buffer.concat(n).toString(`utf8`)})})});a.setTimeout(3e4,()=>{a.destroy(Error(`Timed out after 30000ms while contacting ${e.toString()}`))}),a.on(`error`,e=>{n(e)}),r!==void 0&&a.write(r),a.end()})}async request(e,t){let n=new URL(this.buildUrl(e)),r=t?.method??`GET`,i=typeof t?.body==`string`?t.body:void 0,a=this.toHeaderRecord(this.buildHeaders(i!==void 0));try{let e=await this.sendRequest(n,r,a,i);if(e.statusCode>=200&&e.statusCode<300)return e.body;throw new T(e.statusCode,e.statusMessage,r,n.toString(),e.body)}catch(e){throw e instanceof T?e:Error(this.formatNetworkError(r,n.toString(),e),{cause:e instanceof Error?e:void 0})}}async requestJson(e,t){let n=await this.request(e,t);return JSON.parse(n)}};function se(e){if(!(typeof e.externalId!=`string`||e.externalId.length===0||typeof e.message!=`string`||e.message.length===0||typeof e.severity!=`string`))return w({externalId:e.externalId,path:e.path,line:e.line,message:e.message,severity:e.severity,type:e.type,link:e.link})}function ce(e){return e.annotations??e.values??[]}function le(e){return typeof e.totalCount==`number`&&Number.isFinite(e.totalCount)?e.totalCount:ce(e).length}function E(e){if(e.data!==void 0&&e.data.length>6)throw Error(`Bitbucket Code Insights supports at most 6 report data fields, but got ${e.data.length}.`)}var ue=class{projectKey;repoSlug;logger;request;requestJson;constructor(e,t,n,r,i){this.projectKey=e,this.repoSlug=t,this.logger=n,this.request=r,this.requestJson=i}async getCodeInsightsReport(e,t){let n=`/rest/insights/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/commits/${encodeURIComponent(e)}/reports/${encodeURIComponent(t)}`;try{return await this.requestJson(n)}catch(e){if(e instanceof T&&e.statusCode===404)return;throw e}}async listCodeInsightsAnnotations(e,t){let n=0,r=[];for(;;){let i=`/rest/insights/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/commits/${encodeURIComponent(e)}/reports/${encodeURIComponent(t)}/annotations?limit=1000&start=${n}`,a=await this.requestJson(i),o=ce(a);a.totalCount&&o.length===0&&this.logger.debug(`Bitbucket returned annotation totalCount=${a.totalCount} but no annotation bodies for report ${t} on commit ${e}`);for(let e of o){let t=se(e);t&&r.push(t)}if(a.isLastPage===!0||a.nextPageStart===void 0)return r;n=a.nextPageStart}}async getCodeInsightsAnnotationCount(e,t){let n=0,r=0;for(;;){let i=`/rest/insights/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/commits/${encodeURIComponent(e)}/reports/${encodeURIComponent(t)}/annotations?limit=1000&start=${n}`,a=await this.requestJson(i);if(r+=le(a),a.isLastPage===!0||a.nextPageStart===void 0)return r;n=a.nextPageStart}}async deleteReport(e,t){let n=`/rest/insights/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/commits/${encodeURIComponent(e)}/reports/${encodeURIComponent(t)}`;try{await this.request(n,{method:`DELETE`})}catch(e){if(e instanceof T&&e.statusCode===404){this.logger.debug(`No existing Code Insights report found for ${t}`);return}throw e}}async createReport(e,t,n){E(n);let r=`/rest/insights/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/commits/${encodeURIComponent(e)}/reports/${encodeURIComponent(t)}`;await this.request(r,{method:`PUT`,body:JSON.stringify(n)})}async addAnnotations(e,t,n){if(n.length===0)return;let r=`/rest/insights/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/commits/${encodeURIComponent(e)}/reports/${encodeURIComponent(t)}/annotations`;await this.request(r,{method:`POST`,body:JSON.stringify({annotations:n})})}async publishCodeInsights(e,t,n,r){this.logger.info(`Publishing Code Insights report ${t} for commit ${e}`),E(n),await this.deleteReport(e,t),await this.createReport(e,t,n),await this.addAnnotations(e,t,r)}};const D=32e3;function O(e,t,n={}){if(e.length<=t)return e;let r=n.suffix??`... truncated ...`,i=n.preserveMaxLength?Math.max(0,t-r.length):t;return`${e.slice(0,i).trimEnd()}${r}`}function de(e,t,n){let r=e.split(/\r?\n/),i=Math.max(1,t),a=Math.min(r.length,Math.max(i,n)),o=String(a).length;return r.slice(i-1,a).map((e,t)=>`${String(i+t).padStart(o,` `)}: ${e}`).join(`
|
|
4
|
+
`)}function k(e){if(e.trim().length===0)throw Error(`Pull request comment text must not be empty.`);if(e.length>32e3)throw Error(`Pull request comment text exceeds the local Bitbucket safety limit of ${D} characters (${e.length}).`)}function A(e){return e.updatedDate??e.createdDate??0}function fe(e,t){let n=A(t)-A(e);if(n!==0)return n;let r=t.version-e.version;return r===0?t.id-e.id:r}function pe(e){return e instanceof Error?e.message:String(e)}function me(e){if(!(e instanceof T)||e.statusCode!==409)return!1;let t=`${e.responseBody}\n${e.message}`;return t.includes(`CommentDeletionException`)||/replies which must be deleted first/i.test(t)}function he(e){if(!(e instanceof T)||e.statusCode!==400)return!1;let t=`${e.responseBody}\n${e.message}`;return/cannot be deleted from resolved thread/i.test(t)}var ge=class{projectKey;repoSlug;prId;logger;request;requestJson;constructor(e,t,n,r,i,a){this.projectKey=e,this.repoSlug=t,this.prId=n,this.logger=r,this.request=i,this.requestJson=a}async listPullRequestComments(){let e=new Map,t=0;for(;;){let n=`/rest/api/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/pull-requests/${this.prId}/activities?limit=1000&start=${t}`,r=await this.requestJson(n);for(let t of r.values??[]){if(t.action!==`COMMENTED`||!t.comment)continue;let n=w({id:t.comment.id,text:t.comment.text??``,version:t.comment.version,createdDate:t.comment.createdDate??t.createdDate,updatedDate:t.comment.updatedDate??t.comment.createdDate??t.createdDate}),r=e.get(n.id);(!r||r.version<n.version||r.version===n.version&&A(r)<A(n))&&e.set(n.id,n)}if(r.isLastPage===!0||r.nextPageStart===void 0)break;t=r.nextPageStart}return[...e.values()]}async listPullRequestCommentsByTag(e){let t=`<!-- ${e} -->`;return(await this.listPullRequestComments()).filter(e=>e.text.includes(t)).sort(fe)}async findPullRequestCommentByTag(e){return(await this.listPullRequestCommentsByTag(e))[0]}async createPullRequestComment(e){k(e);let t=`/rest/api/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/pull-requests/${this.prId}/comments`;await this.request(t,{method:`POST`,body:JSON.stringify({text:e})})}async updatePullRequestComment(e,t,n){k(n);let r=`/rest/api/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/pull-requests/${this.prId}/comments/${e}`;await this.request(r,{method:`PUT`,body:JSON.stringify({version:t,text:n})})}async deletePullRequestComment(e,t){let n=`/rest/api/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/pull-requests/${this.prId}/comments/${e}?version=${encodeURIComponent(String(t))}`;await this.request(n,{method:`DELETE`})}async upsertPullRequestComment(e,t,n={}){let r=n.strategy??`update`,i=await this.listPullRequestCommentsByTag(e),a=i[0];if(!a){this.logger.info(`Creating pull request summary comment tagged ${e}`),await this.createPullRequestComment(t);return}if(r===`recreate`){this.logger.info(`Creating replacement pull request summary comment tagged ${e}`),await this.createPullRequestComment(t);for(let t of i)try{this.logger.info(`Deleting superseded pull request summary comment ${t.id} tagged ${e}`),await this.deletePullRequestComment(t.id,t.version)}catch(n){let r=me(n),i=he(n);if(r||i)try{this.logger.info(r?`Superseded pull request summary comment ${t.id} tagged ${e} has replies; archiving it instead of deleting`:`Superseded pull request summary comment ${t.id} tagged ${e} is in a resolved thread; archiving it instead of deleting`),await this.updatePullRequestComment(t.id,t.version,`_Superseded by a newer automated PR review summary. This thread is preserved because Bitbucket will not delete it._`);continue}catch(n){r?this.logger.warn(`Failed to archive superseded pull request summary comment ${t.id} tagged ${e} after delete was blocked by replies: ${pe(n)}`):this.logger.debug(`Superseded pull request summary comment ${t.id} tagged ${e} is in a resolved thread and could not be archived after delete was blocked; leaving it in place: ${pe(n)}`);continue}this.logger.warn(`Failed to delete superseded pull request summary comment ${t.id} tagged ${e}: ${pe(n)}`)}return}this.logger.info(`Updating pull request summary comment tagged ${e}`),await this.updatePullRequestComment(a.id,a.version,t)}};function j(e){let t=e.links?.clone??[];return t.find(e=>(e.name??``).toLowerCase().includes(`http`))?.href??t[0]?.href}function _e(e){let t=j(e.fromRef.repository),n=j(e.toRef.repository),r=e.links?.self?.[0]?.href,i=w({repositoryId:e.fromRef.repository.id,projectKey:e.fromRef.repository.project.key,repoSlug:e.fromRef.repository.slug,cloneUrl:t,refId:e.fromRef.id,displayId:e.fromRef.displayId,latestCommit:e.fromRef.latestCommit}),a=w({repositoryId:e.toRef.repository.id,projectKey:e.toRef.repository.project.key,repoSlug:e.toRef.repository.slug,cloneUrl:n,refId:e.toRef.id,displayId:e.toRef.displayId,latestCommit:e.toRef.latestCommit});return w({id:e.id,version:e.version,state:e.state,draft:e.draft,title:e.title,description:e.description?.trim()||``,link:r,source:i,target:a})}var ve=class{projectKey;repoSlug;prId;requestJson;constructor(e,t,n,r){this.projectKey=e,this.repoSlug=t,this.prId=n,this.requestJson=r}async getPullRequest(){let e=`/rest/api/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/pull-requests/${this.prId}`;return _e(await this.requestJson(e))}},ye=class{projectKey;repoSlug;requestJson;constructor(e,t,n){this.projectKey=e,this.repoSlug=t,this.requestJson=n}async listPullRequests(e){let t=0,n=[];for(;;){let r=new URLSearchParams({limit:`1000`,start:String(t)});e!==void 0&&r.set(`state`,e);let i=`/rest/api/latest/projects/${encodeURIComponent(this.projectKey)}/repos/${encodeURIComponent(this.repoSlug)}/pull-requests?${r.toString()}`,a=await this.requestJson(i);for(let e of a.values??[])n.push(_e(e));if(a.isLastPage===!0||a.nextPageStart===void 0)return n;t=a.nextPageStart}}async listOpenPullRequests(){return this.listPullRequests(`OPEN`)}},be=class{transport;pullRequests;comments;codeInsights;constructor(e,t){this.transport=new oe(e),this.pullRequests=new ve(e.projectKey,e.repoSlug,e.prId,this.transport.requestJson.bind(this.transport)),this.comments=new ge(e.projectKey,e.repoSlug,e.prId,t,this.transport.request.bind(this.transport),this.transport.requestJson.bind(this.transport)),this.codeInsights=new ue(e.projectKey,e.repoSlug,t,this.transport.request.bind(this.transport),this.transport.requestJson.bind(this.transport))}async getPullRequest(){return this.pullRequests.getPullRequest()}async getCodeInsightsReport(e,t){return this.codeInsights.getCodeInsightsReport(e,t)}async getCodeInsightsAnnotationCount(e,t){return this.codeInsights.getCodeInsightsAnnotationCount(e,t)}async listCodeInsightsAnnotations(e,t){return this.codeInsights.listCodeInsightsAnnotations(e,t)}async listPullRequestComments(){return this.comments.listPullRequestComments()}async findPullRequestCommentByTag(e){return this.comments.findPullRequestCommentByTag(e)}async createPullRequestComment(e){return this.comments.createPullRequestComment(e)}async updatePullRequestComment(e,t,n){return this.comments.updatePullRequestComment(e,t,n)}async upsertPullRequestComment(e,t,n){return this.comments.upsertPullRequestComment(e,t,n)}async deleteReport(e,t){return this.codeInsights.deleteReport(e,t)}async createReport(e,t,n){return this.codeInsights.createReport(e,t,n)}async addAnnotations(e,t,n){return this.codeInsights.addAnnotations(e,t,n)}async publishCodeInsights(e,t,n,r){return this.codeInsights.publishCodeInsights(e,t,n,r)}},xe=class{pullRequests;constructor(e){let t=new oe({...e,prId:1});this.pullRequests=new ye(e.projectKey,e.repoSlug,t.requestJson.bind(t))}async listOpenPullRequests(){return this.pullRequests.listOpenPullRequests()}},M=class extends Error{constructor(e){super(e),this.name=`CliUserError`}};function Se(e){return e instanceof M}const N=[`low`,`medium`,`high`],Ce=[`debug`,`info`,`warn`,`error`],we=[`basic`,`bearer`],Te=[`low`,`medium`,`high`,`xhigh`],Ee=[`update`,`recreate`];function De(e){return e.env!==void 0&&e.envParser!==void 0}function Oe(e){return e.repoOverride===!0}function ke(e){return De(e)&&Oe(e)}function P(e,t={}){return{docs:{order:e,...t}}}function F(e){return{envParser:e}}function I(){return{repoOverride:!0}}const Ae={repoRoot:{path:`repoRoot`,env:`REPO_ROOT`,description:`Path to the repository under review.`,...F({kind:`string`}),...P(9,{defaultText:`current working directory`})},gitRemoteName:{path:`gitRemoteName`,env:`GIT_REMOTE_NAME`,description:`Git remote name used to fetch PR commits.`,...F({kind:`string`}),...P(10,{defaultValuePath:[`gitRemoteName`]})},logLevel:{path:`logLevel`,env:`LOG_LEVEL`,description:`Logger verbosity.`,...F({kind:`enum`,values:Ce}),...P(11,{defaultValuePath:[`logLevel`]})},bitbucketAuthType:{path:`bitbucket.auth.type`,env:`BITBUCKET_AUTH_TYPE`,description:`Bitbucket authentication strategy.`,...F({kind:`enum`,values:we}),...P(12,{defaultText:`auto-detected from provided credentials`})},bitbucketToken:{path:`bitbucket.auth.token`,env:`BITBUCKET_TOKEN`,description:`Bitbucket bearer token.`,...F({kind:`string`}),...P(6,{defaultText:`required unless basic auth vars are used`})},bitbucketUsername:{path:`bitbucket.auth.username`,env:`BITBUCKET_USERNAME`,description:`Bitbucket basic auth username.`,...F({kind:`string`}),...P(7,{defaultText:"required with `BITBUCKET_PASSWORD` for basic auth"})},bitbucketPassword:{path:`bitbucket.auth.password`,env:`BITBUCKET_PASSWORD`,description:`Bitbucket basic auth password.`,...F({kind:`string`}),...P(8,{defaultText:"required with `BITBUCKET_USERNAME` for basic auth"})},bitbucketCaCertPath:{path:`bitbucket.tls.caCertPath`,env:`BITBUCKET_CA_CERT_PATH`,description:`PEM CA bundle path for Bitbucket TLS.`,...F({kind:`string`}),...P(13,{defaultText:`-`})},bitbucketInsecureTls:{path:`bitbucket.tls.insecureSkipVerify`,env:`BITBUCKET_INSECURE_TLS`,description:`Skip strict TLS verification for Bitbucket.`,...F({kind:`boolean`}),...P(14,{defaultValuePath:[`bitbucket`,`tls`,`insecureSkipVerify`]})},copilotModel:{path:`copilot.model`,env:`COPILOT_MODEL`,description:`Copilot model override.`,...F({kind:`string`}),...I(),...P(15,{defaultValuePath:[`copilot`,`model`]})},copilotReasoningEffort:{path:`copilot.reasoningEffort`,env:`COPILOT_REASONING_EFFORT`,description:`Copilot reasoning effort.`,...F({kind:`enum`,values:Te}),...I(),...P(16,{defaultValuePath:[`copilot`,`reasoningEffort`]})},copilotTimeoutMs:{path:`copilot.timeoutMs`,env:`COPILOT_TIMEOUT_MS`,description:`Copilot timeout in milliseconds.`,...F({kind:`positiveInteger`}),...I(),...P(17,{defaultValuePath:[`copilot`,`timeoutMs`]})},reportKey:{path:`report.key`,env:`REPORT_KEY`,description:`Code Insights report key.`,...F({kind:`string`}),...P(19,{defaultValuePath:[`report`,`key`]})},reportTitle:{path:`report.title`,env:`REPORT_TITLE`,description:`Code Insights report title.`,...F({kind:`string`}),...I(),...P(20,{defaultValuePath:[`report`,`title`]})},reporterName:{path:`report.reporter`,env:`REPORTER_NAME`,description:`Displayed report publisher name.`,...F({kind:`string`}),...P(21,{defaultValuePath:[`report`,`reporter`]})},reportCommentTag:{path:`report.commentTag`,env:`REPORT_COMMENT_TAG`,description:`Tag used to locate the PR summary comment.`,...F({kind:`string`}),...P(22,{defaultValuePath:[`report`,`commentTag`]})},reportCommentStrategy:{path:`report.commentStrategy`,env:`REPORT_COMMENT_STRATEGY`,description:`How the tagged PR summary comment is updated.`,...F({kind:`enum`,values:Ee}),...I(),...P(23,{defaultValuePath:[`report`,`commentStrategy`]})},reportLink:{path:`report.link`,env:`REPORT_LINK`,description:`Code Insights report link.`,...F({kind:`string`}),...P(24,{defaultText:"falls back to `BUILD_URL` when present"})},buildUrl:{path:`report.link`,env:`BUILD_URL`,description:`Fallback report link from CI build URL.`,...F({kind:`string`}),...P(24.1,{defaultText:"used when `REPORT_LINK` is unset"})},reviewDryRun:{path:`review.dryRun`,description:`Run without publishing results to Bitbucket.`},reviewForce:{path:`review.forceReview`,env:`REVIEW_FORCE`,description:`Force review even when the revision was already published.`,...F({kind:`boolean`}),...P(25,{defaultValuePath:[`review`,`forceReview`]})},reviewConfirmRerun:{path:`review.confirmRerun`,description:`Prompt before rerunning unusable cached artifacts.`},reviewMaxFiles:{path:`review.maxFiles`,env:`REVIEW_MAX_FILES`,description:`Maximum number of changed files to review.`,...F({kind:`positiveInteger`}),...I(),...P(26,{defaultValuePath:[`review`,`maxFiles`]})},reviewMaxFindings:{path:`review.maxFindings`,env:`REVIEW_MAX_FINDINGS`,description:`Maximum number of findings to publish.`,...F({kind:`positiveInteger`}),...I(),...P(27,{defaultValuePath:[`review`,`maxFindings`]})},reviewMinConfidence:{path:`review.minConfidence`,env:`REVIEW_MIN_CONFIDENCE`,description:`Minimum confidence threshold for findings.`,...F({kind:`enum`,values:N}),...I(),...P(28,{defaultValuePath:[`review`,`minConfidence`]})},reviewMaxPatchChars:{path:`review.maxPatchChars`,env:`REVIEW_MAX_PATCH_CHARS`,description:`Maximum diff size sent to Copilot per file.`,...F({kind:`positiveInteger`}),...I(),...P(29,{defaultValuePath:[`review`,`maxPatchChars`]})},reviewDefaultFileSliceLines:{path:`review.defaultFileSliceLines`,env:`REVIEW_DEFAULT_FILE_SLICE_LINES`,description:`Default line window when reading file slices.`,...F({kind:`positiveInteger`}),...I(),...P(30,{defaultValuePath:[`review`,`defaultFileSliceLines`]})},reviewMaxFileSliceLines:{path:`review.maxFileSliceLines`,env:`REVIEW_MAX_FILE_SLICE_LINES`,description:`Maximum line window for file slices.`,...F({kind:`positiveInteger`}),...I(),...P(31,{defaultValuePath:[`review`,`maxFileSliceLines`]})},reviewIgnorePaths:{path:`review.ignorePaths`,env:`REVIEW_IGNORE_PATHS`,description:`Comma-separated repo-relative glob patterns to skip.`,...F({kind:`stringArray`}),...I(),...P(32,{defaultValuePath:[`review`,`ignorePaths`]})},reviewSkipBranchPrefixes:{path:`review.skipBranchPrefixes`,env:`REVIEW_SKIP_BRANCH_PREFIXES`,description:`Comma-separated source branch prefixes that should be skipped.`,...F({kind:`stringArray`}),...I(),...P(33,{defaultValuePath:[`review`,`skipBranchPrefixes`]})},ciSummaryPath:{path:`ciSummaryPath`,env:`CI_SUMMARY_PATH`,description:`Path to a CI summary file included in review context.`,...F({kind:`string`}),...P(18,{defaultText:`-`})}},L={flags:[`-h`,`--help`],description:`Show this help text`},je={review:{usage:`review <pull-request-url> [options]`,description:`Review one pull request from an explicit Bitbucket URL`,argumentLabel:`<pull-request-url>`,argumentDescription:`Bitbucket pull request URL, for example https://host/projects/PROJ/repos/repo/pull-requests/123.`},batch:{usage:`batch <repository-url> [options]`,description:`Review all open pull requests for one Bitbucket repository URL`,argumentLabel:`<repository-url>`,argumentDescription:`Bitbucket repository URL, for example https://host/projects/PROJ/repos/my-repo.`}},Me={dryRun:{flags:[`--dry-run`],description:`Run without publishing results to Bitbucket`},forceReview:{flags:[`--force-review`],description:`Re-run even if the current PR revision already has published results`},confirmRerun:{flags:[`--confirm-rerun`],description:`Ask before rerunning unusable cached artifacts for an unchanged PR revision`},repoRoot:{flags:[`--repo-root`],description:`Use a different local checkout as the repository root`,valueLabel:`<path>`},help:L},R={dryRun:{flags:[`--dry-run`],description:`Run without publishing results to Bitbucket`},forceReview:{flags:[`--force-review`],description:`Re-run even if the current PR revision already has published results`},tempRoot:{flags:[`--temp-root`],description:`Parent directory for mirror and workspace clones`,valueLabel:`<path>`},maxParallel:{flags:[`--max-parallel`],description:`Maximum concurrent review workers`,valueLabel:`<count>`},keepWorkdirs:{flags:[`--keep-workdirs`],description:`Keep per-PR workdirs after the run completes`},help:L};function Ne(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function z(e){return e.split(`.`)}function Pe(e){return typeof e==`string`?z(e):e}function B(e){return Array.isArray(e)?[...e]:e}function V(e,t){let n=e;for(let e of Pe(t)){if(!Ne(n)||!(e in n))return;n=n[e]}return B(n)}function Fe(e,t){let n=e[t];if(Ne(n))return n;let r={};return e[t]=r,r}function Ie(e,t,n){let r=Pe(t),i=e;for(let e of r.slice(0,-1))i=Fe(i,e);let a=r[r.length-1];a!==void 0&&(i[a]=B(n))}function Le(e){return e===`copilot`||e===`report`||e===`review`}function Re(e){let[t,...n]=z(e);if(t===void 0||!Le(t)||n.length===0)throw Error(`Repo override metadata path ${e} must target copilot, report, or review fields.`);return[t,...n]}const ze=Object.values(Ae).flatMap(e=>Oe(e)?[Re(e.path)]:[]);function Be(e){let t=Ge();for(let n of ze){let r=e(n);r!==void 0&&Ie(t,n,r)}return Ke(t)}const Ve=p.object({copilot:p.object({model:p.string().min(1).optional(),reasoningEffort:p.enum(Te).optional(),timeoutMs:p.number().int().positive().optional()}).strict(),report:p.object({title:p.string().min(1).optional(),commentStrategy:p.enum(Ee).optional()}).strict(),review:p.object({maxFiles:p.number().int().positive().optional(),maxFindings:p.number().int().positive().optional(),minConfidence:p.enum(N).optional(),maxPatchChars:p.number().int().positive().optional(),defaultFileSliceLines:p.number().int().positive().optional(),maxFileSliceLines:p.number().int().positive().optional(),ignorePaths:p.array(p.string().min(1)).optional(),skipBranchPrefixes:p.array(p.string().min(1)).optional()}).strict()}).strict(),He=p.object({repoRoot:p.string().min(1),gitRemoteName:p.string().min(1),logLevel:p.enum(Ce),bitbucket:p.object({baseUrl:p.string().min(1),projectKey:p.string().min(1),repoSlug:p.string().min(1),prId:p.number().int().positive(),auth:p.discriminatedUnion(`type`,[p.object({type:p.literal(`bearer`),token:p.string().min(1)}).strict(),p.object({type:p.literal(`basic`),username:p.string().min(1),password:p.string().min(1)}).strict()]),tls:p.object({caCertPath:p.string().min(1).optional(),insecureSkipVerify:p.boolean()}).strict()}).strict(),copilot:p.object({model:p.string().min(1),reasoningEffort:p.enum(Te),timeoutMs:p.number().int().positive()}).strict(),report:p.object({key:p.string().min(1),title:p.string().min(1),reporter:p.string().min(1),link:p.string().min(1).optional(),commentTag:p.string().min(1),commentStrategy:p.enum(Ee)}).strict(),review:p.object({dryRun:p.boolean(),forceReview:p.boolean(),confirmRerun:p.boolean(),maxFiles:p.number().int().positive(),maxFindings:p.number().int().positive(),minConfidence:p.enum(N),maxPatchChars:p.number().int().positive(),defaultFileSliceLines:p.number().int().positive(),maxFileSliceLines:p.number().int().positive(),ignorePaths:p.array(p.string().min(1)),skipBranchPrefixes:p.array(p.string().min(1))}).strict(),ciSummaryPath:p.string().min(1).optional(),internal:p.object({envRepoOverrides:Ve,trustedRepoConfig:p.object({path:p.string().min(1),commit:p.string().min(1)}).strict().optional()}).strict().optional()}).strict().superRefine((e,t)=>{e.review.defaultFileSliceLines>e.review.maxFileSliceLines&&t.addIssue({code:p.ZodIssueCode.custom,path:[`review`,`defaultFileSliceLines`],message:`review.defaultFileSliceLines must be less than or equal to review.maxFileSliceLines.`})});function Ue(e){return e.issues.map(e=>`${e.path.length>0?e.path.join(`.`):`config`}: ${e.message}`).join(`
|
|
5
|
+
`)}function We(e){return Be(t=>V(e,t))}function Ge(){return{copilot:{},report:{},review:{}}}function Ke(e){let t=Ve.safeParse(e);if(t.success)return t.data;throw new M(Ue(t.error))}function qe(e){return Be(t=>V(e,t))}function Je(e,t){return Be(n=>{let r=V(e,n);return r===void 0?V(t,n):r})}function Ye(e){return{...e,copilot:{...e.copilot},report:{...e.report},review:{...e.review},...e.internal?{internal:{...e.internal,envRepoOverrides:We(e.internal.envRepoOverrides)}}:{}}}function Xe(e,t){let n=Ye(e);for(let e of ze){let r=V(t,e);r!==void 0&&Ie(n,e,r)}return n}function Ze(e){let t=He.safeParse(e);if(t.success)return t.data;throw new M(Ue(t.error))}function Qe(e,t){return Ze(Xe(e,Je(t,qe(e))))}const $e=/[^A-Za-z0-9._-]+/g;function et(e){if(typeof e!=`string`)return;let t=e.trim();return t.length>0?t:void 0}function tt(){return p.preprocess(et,p.string().optional())}function nt(e,t,n){if(!/^\d+$/.test(t))return n.addIssue({code:p.ZodIssueCode.custom,message:`${e} must be a positive integer.`}),p.NEVER;let r=Number.parseInt(t,10);return!Number.isSafeInteger(r)||r<=0?(n.addIssue({code:p.ZodIssueCode.custom,message:`${e} must be a positive integer.`}),p.NEVER):r}function rt(e){return tt().transform(e=>{if(e!==void 0)return e})}function it(e,t){return tt().transform((n,r)=>{if(n!==void 0)return t.includes(n)?n:(r.addIssue({code:p.ZodIssueCode.custom,message:`${e} must be one of: ${t.join(`, `)}.`}),p.NEVER)})}function at(e){return tt().transform((t,n)=>{if(t!==void 0)return nt(e,t,n)})}function ot(e){return tt().transform((t,n)=>{if(t===void 0)return;let r=t.toLowerCase();return[`1`,`true`,`yes`,`y`,`on`].includes(r)?!0:[`0`,`false`,`no`,`n`,`off`].includes(r)?!1:(n.addIssue({code:p.ZodIssueCode.custom,message:`${e} must be a boolean value such as true/false or 1/0.`}),p.NEVER)})}function st(e){return tt().transform((t,n)=>{if(t===void 0)return;let r=t.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);return r.length===0?(n.addIssue({code:p.ZodIssueCode.custom,message:`${e} must contain at least one non-empty value when provided.`}),p.NEVER):r})}function ct(e){switch(e.envParser.kind){case`string`:return rt(e.env);case`enum`:return it(e.env,e.envParser.values);case`positiveInteger`:return at(e.env);case`boolean`:return ot(e.env);case`stringArray`:return st(e.env)}throw Error(`Unsupported environment parser for ${e.env}.`)}function lt(e){let t={};for(let n of Object.values(e))De(n)&&(t[n.env]=ct(n));return t}function ut(){return Object.values(Ae).reduce((e,t)=>(ke(t)&&(e[t.env]=z(t.path)),e),{})}function dt(e,t){if(e===void 0)throw new M(t);return e}const ft=lt(Ae),pt=ut(),mt=p.object(ft).superRefine((e,t)=>{let n=e.BITBUCKET_TOKEN!==void 0,r=e.BITBUCKET_USERNAME!==void 0,i=e.BITBUCKET_PASSWORD!==void 0,a=(e,n)=>{t.addIssue(w({code:p.ZodIssueCode.custom,message:e,path:n?[n]:void 0}))};if(e.BITBUCKET_AUTH_TYPE===`basic`){r||a(`BITBUCKET_USERNAME is required when BITBUCKET_AUTH_TYPE=basic.`,`BITBUCKET_USERNAME`),i||a(`BITBUCKET_PASSWORD is required when BITBUCKET_AUTH_TYPE=basic.`,`BITBUCKET_PASSWORD`);return}if(e.BITBUCKET_AUTH_TYPE===`bearer`){n||a(`BITBUCKET_TOKEN is required when BITBUCKET_AUTH_TYPE=bearer.`,`BITBUCKET_TOKEN`);return}if(!n){if(r||i){r||a(`BITBUCKET_USERNAME is required when using basic Bitbucket authentication.`,`BITBUCKET_USERNAME`),i||a(`BITBUCKET_PASSWORD is required when using basic Bitbucket authentication.`,`BITBUCKET_PASSWORD`);return}a(`Provide BITBUCKET_TOKEN or BITBUCKET_USERNAME and BITBUCKET_PASSWORD for Bitbucket authentication.`)}});function ht(e){let t=e.trim().replace($e,`-`).replace(/-+/g,`-`).replace(/^[-.]+|[-.]+$/g,``);if(t.length===0)return`copilot-pr-review`;if(t.length<=50)return t;let n=`-${f(`sha1`).update(t).digest(`hex`).slice(0,10)}`,r=Math.max(1,50-n.length);return`${t.slice(0,r)}${n}`}function gt(e){let t=Ge();for(let[n,r]of Object.entries(pt)){let i=e[n];i!==void 0&&Ie(t,r,i)}return t}function _t(e){return e.issues.map(e=>e.message).join(`
|
|
6
|
+
`)}function vt(e,t){return dt(e,t)}function yt(e){let t=mt.safeParse(e);if(t.success)return t.data;throw new M(_t(t.error))}function H(e){let t=Ae[e];if(!(`env`in t)||t.env===void 0)throw new M(`Metadata field ${String(e)} does not define an env key.`);return t.env}function bt(e,t){try{return new URL(e.trim())}catch{throw new M(`${t} must be a valid absolute http(s) URL.`)}}function xt(e){let t=e.replace(/\/+/g,`/`).replace(/\/+$/,``);return t.length===0?`/`:t}function St(e,t){if(!/^\d+$/.test(e))throw new M(`${t} must end with a numeric pull request id.`);let n=Number.parseInt(e,10);if(!Number.isSafeInteger(n)||n<=0)throw new M(`${t} must end with a numeric pull request id.`);return n}function Ct(e,t){let n=t.length>0?`/${t.join(`/`)}`:``;return`${e.origin}${n}`}function wt(e){let t=xt(e.url.pathname).split(`/`).filter(e=>e.length>0),n=t.indexOf(`projects`);if(n<0)throw new M(e.requirePullRequestId?`${e.label} must point to a pull request page like https://host/projects/PROJ/repos/repo/pull-requests/123.`:`${e.label} must point to a repository page like https://host/projects/PROJ/repos/repo.`);let r=t[n+1],i=t[n+2],a=t[n+3];if(r===void 0||i!==`repos`||a===void 0)throw new M(e.requirePullRequestId?`${e.label} must point to a pull request page like https://host/projects/PROJ/repos/repo/pull-requests/123.`:`${e.label} must point to a repository page like https://host/projects/PROJ/repos/repo.`);let o=t.slice(0,n);if(!e.requirePullRequestId){if(t.length!==n+4)throw new M(`${e.label} must point to a repository page like https://host/projects/PROJ/repos/repo.`);return{prefixSegments:o,projectKey:r,repoSlug:a}}let s=t[n+4],c=t[n+5];if(s!==`pull-requests`||c===void 0||t.length!==n+6)throw new M(`${e.label} must point to a pull request page like https://host/projects/PROJ/repos/repo/pull-requests/123.`);return{prefixSegments:o,projectKey:r,repoSlug:a,prId:St(c,e.label)}}function Tt(e){let t=bt(e,`Repository URL`);if(t.protocol!==`http:`&&t.protocol!==`https:`)throw new M(`Repository URL must use http or https.`);let n=wt({url:t,label:`Repository URL`,requirePullRequestId:!1}),r=Ct(t,n.prefixSegments),i=`${r}/projects/${n.projectKey}/repos/${n.repoSlug}`;return{baseUrl:r,projectKey:n.projectKey,repoSlug:n.repoSlug,repositoryUrl:i}}function Et(e){let t=bt(e,`Pull request URL`);if(t.protocol!==`http:`&&t.protocol!==`https:`)throw new M(`Pull request URL must use http or https.`);let n=wt({url:t,label:`Pull request URL`,requirePullRequestId:!0});if(n.prId===void 0)throw new M(`Pull request URL must include a numeric pull request id.`);let r=Ct(t,n.prefixSegments),i=`${r}/projects/${n.projectKey}/repos/${n.repoSlug}`,a=`${i}/pull-requests/${n.prId}`;return{baseUrl:r,projectKey:n.projectKey,repoSlug:n.repoSlug,prId:n.prId,repositoryUrl:i,pullRequestUrl:a}}function Dt(e){return`${Tt(`${e.baseUrl}/projects/${e.projectKey}/repos/${e.repoSlug}`).repositoryUrl}/pull-requests/${e.prId}`}function Ot(e){if(e.BITBUCKET_AUTH_TYPE===`basic`)return{type:`basic`,username:vt(e.BITBUCKET_USERNAME,`${H(`bitbucketUsername`)} is required when ${H(`bitbucketAuthType`)}=basic.`),password:vt(e.BITBUCKET_PASSWORD,`${H(`bitbucketPassword`)} is required when ${H(`bitbucketAuthType`)}=basic.`)};if(e.BITBUCKET_AUTH_TYPE===`bearer`)return{type:`bearer`,token:vt(e.BITBUCKET_TOKEN,`${H(`bitbucketToken`)} is required when ${H(`bitbucketAuthType`)}=bearer.`)};if(e.BITBUCKET_TOKEN!==void 0)return{type:`bearer`,token:e.BITBUCKET_TOKEN};if(e.BITBUCKET_USERNAME!==void 0||e.BITBUCKET_PASSWORD!==void 0)return{type:`basic`,username:vt(e.BITBUCKET_USERNAME,`${H(`bitbucketUsername`)} is required when using basic Bitbucket authentication.`),password:vt(e.BITBUCKET_PASSWORD,`${H(`bitbucketPassword`)} is required when using basic Bitbucket authentication.`)};throw new M(`Provide ${H(`bitbucketToken`)} or ${H(`bitbucketUsername`)} and ${H(`bitbucketPassword`)} for Bitbucket authentication.`)}function kt(e){return{baseUrl:e.location.baseUrl,projectKey:e.location.projectKey,repoSlug:e.location.repoSlug,prId:e.location.prId,auth:Ot(e.env),tls:w({caCertPath:e.caCertPath,insecureSkipVerify:e.runtimeConfig.tls.insecureSkipVerify})}}function At(e){let t=/^([^:]+:)?(.+?):(\d+):(.*)$/.exec(e);if(!t)return;let n=t[2],r=Number.parseInt(t[3]??`0`,10),i=t[4]??``;if(!(!n||!Number.isFinite(r)||r<=0))return{path:n,line:r,text:i}}const jt=m(n),Mt=[`-c`,`core.quotePath=false`];function Nt(e){return e===0}var Pt=class e{repoRoot;logger;remoteName;telemetry;constructor(e,t,n){this.repoRoot=e,this.logger=t,this.remoteName=n,this.telemetry={byOperation:{}}}describeGitOperation(e){return e[0]===`remote`&&e[1]===`get-url`?`remote.get-url`:e[0]===`cat-file`&&e[1]===`-e`?`cat-file.exists`:e[0]===`cat-file`&&e[1]===`-t`?`cat-file.type`:e[0]??`unknown`}recordGitOperationDuration(e,t){let n=this.telemetry.byOperation[e]??{count:0,durationMsTotal:0};this.telemetry.byOperation[e]={count:n.count+1,durationMsTotal:n.durationMsTotal+t}}getTelemetrySnapshot(){return{byOperation:Object.fromEntries(Object.entries(this.telemetry.byOperation).map(([e,t])=>[e,{...t}]))}}async runGitDetailed(e){let t=Date.now();try{let{stdout:t,stderr:n}=await jt(`git`,[...Mt,...e],{cwd:this.repoRoot,encoding:`utf8`,maxBuffer:32*1024*1024});return{stdout:t,stderr:n,exitCode:0}}catch(e){let t=e;if(typeof t.code==`number`)return{stdout:t.stdout??``,stderr:t.stderr??``,exitCode:t.code};throw e}finally{this.recordGitOperationDuration(this.describeGitOperation(e),Date.now()-t)}}async runGitTextSearch(e,t){let n=t!==void 0&&Number.isSafeInteger(t)&&t>0?t:void 0,i=n===void 0?void 0:n+1,a=Date.now();return new Promise((t,o)=>{let s=r(`git`,[...Mt,...e],{cwd:this.repoRoot,stdio:[`ignore`,`pipe`,`pipe`]}),c=new Map,l=``,u=``,d=!1,f=!1,p=!1,m=()=>{f||(f=!0,this.recordGitOperationDuration(this.describeGitOperation(e),Date.now()-a))},h=e=>{p||(p=!0,t(e))},g=e=>{p||(p=!0,o(e))},_=e=>{let t=At(e);if(!t)return;let n=`${t.path}:${t.line}:${t.text}`;c.has(n)||(c.set(n,t),i!==void 0&&c.size>=i&&!d&&(d=!0,s.kill(`SIGTERM`)))},v=e=>{let t=l.indexOf(`
|
|
7
|
+
`);for(;t>=0;){let e=l.slice(0,t).replace(/\r$/,``);l=l.slice(t+1),_(e),t=l.indexOf(`
|
|
8
|
+
`)}e&&l.trim().length>0&&(_(l.replace(/\r$/,``)),l=``)};s.stdout.setEncoding(`utf8`),s.stdout.on(`data`,e=>{l+=e,v(!1)}),s.stderr.setEncoding(`utf8`),s.stderr.on(`data`,e=>{u+=e}),s.on(`error`,e=>{m(),g(e instanceof Error?e:Error(String(e)))}),s.on(`close`,t=>{m(),v(!0);let r=[...c.values()];if(d&&n!==void 0){h({matches:r.slice(0,n),truncated:!0,totalMatches:r.length});return}if(t!==0&&t!==1){g(Error(`Git search failed: git ${e.join(` `)}\n${u||`exit code ${t}`}`));return}h({matches:r,truncated:!1,totalMatches:r.length})})})}async runGit(e,t){let n=await this.runGitDetailed(e);if(n.exitCode===0)return n.stdout;if(t?.allowFailure)return``;throw Error(`Git command failed: git ${e.join(` `)}\n${n.stderr||`exit code ${n.exitCode}`}`)}async checkGitObjectExists(e){return Nt((await this.runGitDetailed([`cat-file`,`-e`,e])).exitCode)}async hasCommit(e){return this.checkGitObjectExists(`${e}^{commit}`)}async getPathTypeAtCommit(e,t){let n=await this.runGitDetailed([`cat-file`,`-t`,`${e}:${t}`]);if(n.exitCode===0)switch(n.stdout.trim()){case`blob`:return`file`;case`tree`:return`directory`;default:return}}async getRemoteUrl(e){return e.includes(`://`)||e.startsWith(`git@`)?e:(await this.runGit([`remote`,`get-url`,e],{allowFailure:!0})).trim()||void 0}static normalizeRemoteUrl(e){return e?.trim().replace(/\.git$/,``)}async ensurePullRequestCommits(e){await this.ensureCommitAvailable(e.target.latestCommit,e.target.refId,e.target.cloneUrl),await this.ensureCommitAvailable(e.source.latestCommit,e.source.refId,e.source.cloneUrl)}async ensureCommitAvailable(t,n,r){if(await this.hasCommit(t))return;let i=[],a=e.normalizeRemoteUrl(await this.getRemoteUrl(this.remoteName)),o=[{source:this.remoteName,ref:n},{source:this.remoteName,ref:t}];if(r){let i=e.normalizeRemoteUrl(r);(!a||i!==a)&&(o.push({source:r,ref:n}),o.push({source:r,ref:t}))}for(let e of o){try{this.logger.debug(`Fetching git object ${t} using ${e.source} ${e.ref}`),await this.runGit([`fetch`,`--no-tags`,`--no-prune`,e.source,e.ref])}catch(e){i.push(e.message)}if(await this.hasCommit(t))return}throw Error(`Unable to make commit ${t} available locally. Tried ref ${n}.\n${i.join(`
|
|
9
|
+
---
|
|
10
|
+
`)}`)}async mergeBase(e,t){return(await this.runGit([`merge-base`,e,t])).trim()}async diff(e,t){return this.runGit([`diff`,`--no-color`,`--find-renames`,`--find-copies`,`--unified=3`,e,t,`--`])}async checkoutDetached(e){await this.runGit([`checkout`,`--detach`,`--force`,e])}async listFilesAtCommit(e,t){let n=(t??[]).filter(e=>e.length>0),r=n.length>0?[`ls-tree`,`-r`,`--name-only`,e,`--`,...n]:[`ls-tree`,`-r`,`--name-only`,e],i=await this.runGit(r);return i.trim().length===0?[]:[...new Set(i.split(/\r?\n/).map(e=>e.trim()).filter(e=>e.length>0))]}async searchTextAtCommit(e,t,n){let r=[`grep`,`-n`,`-I`,`--full-name`];(n?.mode??`literal`)===`literal`?(r.push(`-F`),n?.wholeWord&&r.push(`-w`)):r.push(`-E`),r.push(`-e`,t,e);let i=(n?.directoryPaths??[]).filter(e=>e.length>0);return i.length>0&&r.push(`--`,...i),this.runGitTextSearch(r,n?.limit)}async readTextFileAtCommit(e,t){let n=await this.getPathTypeAtCommit(e,t);if(!n)return{status:`not_found`};if(n!==`file`)return{status:`not_file`};let r=await this.runGit([`show`,`${e}:${t}`]);return r.includes(`\0`)?{status:`not_text`}:{status:`ok`,content:r}}async readFileAtCommit(e,t){let n=await this.readTextFileAtCommit(e,t);return n.status===`ok`?n.content:void 0}};const U={gitRemoteName:`origin`,logLevel:`info`,bitbucket:{tls:{insecureSkipVerify:!0}},copilot:{model:`gpt-5.4`,reasoningEffort:`xhigh`,timeoutMs:18e5},report:{key:`copilot-pr-review`,title:`Copilot PR Review`,reporter:`GitHub Copilot via Jenkins`,commentTag:`copilot-pr-review`,commentStrategy:`recreate`},review:{dryRun:!1,forceReview:!1,confirmRerun:!1,maxFiles:300,maxFindings:25,minConfidence:`medium`,maxPatchChars:12e3,defaultFileSliceLines:250,maxFileSliceLines:400,ignorePaths:[],skipBranchPrefixes:[`renovate/`]}};function Ft(e){return[...new Set([...U.review.skipBranchPrefixes,...e])]}function It(e,t){if(e.draft)return`Skipping review because pull request #${e.id} is a draft.`;for(let n of Ft(t))if(e.source.displayId.startsWith(n))return`Skipping review because pull request #${e.id} source branch ${e.source.displayId} matches skip prefix ${n}.`}const W={schemaRefMaxLength:2048,modelMaxLength:120,reportTitleMaxLength:120,timeoutMs:{min:6e4,max:36e5},maxFiles:{min:1,max:500},maxFindings:{min:1,max:100},maxPatchChars:{min:500,max:5e4},defaultFileSliceLines:{min:1,max:500},maxFileSliceLines:{min:1,max:1e3},ignorePaths:{maxItems:200,maxPatternLength:512},skipBranchPrefixes:{maxItems:50,maxPrefixLength:128}};function Lt(e,t){return p.int(`${e} must be an integer.`).min(t.min,`${e} must be at least ${t.min}.`).max(t.max,`${e} must be at most ${t.max}.`)}const Rt=p.object({maxFiles:Lt(`review.maxFiles`,W.maxFiles).describe(`Maximum number of changed files to review after filtering.`).optional(),maxFindings:Lt(`review.maxFindings`,W.maxFindings).describe(`Maximum number of findings to publish.`).optional(),minConfidence:p.enum(N).describe(`Minimum confidence threshold for reportable findings.`).optional(),maxPatchChars:Lt(`review.maxPatchChars`,W.maxPatchChars).describe(`Maximum diff characters to send for a reviewed file.`).optional(),defaultFileSliceLines:Lt(`review.defaultFileSliceLines`,W.defaultFileSliceLines).describe(`Default line window when reading file content slices.`).optional(),maxFileSliceLines:Lt(`review.maxFileSliceLines`,W.maxFileSliceLines).describe(`Maximum line window allowed for file content slices.`).optional(),ignorePaths:p.array(p.string().min(1,`review.ignorePaths entries must not be empty.`).max(W.ignorePaths.maxPatternLength,`review.ignorePaths entries must be at most ${W.ignorePaths.maxPatternLength} characters.`)).min(1,`review.ignorePaths must contain at least one pattern.`).max(W.ignorePaths.maxItems,`review.ignorePaths must contain at most ${W.ignorePaths.maxItems} patterns.`).describe(`Repo-relative glob patterns for changed files that should be skipped during review.`).optional(),skipBranchPrefixes:p.array(p.string().min(1,`review.skipBranchPrefixes entries must not be empty.`).max(W.skipBranchPrefixes.maxPrefixLength,`review.skipBranchPrefixes entries must be at most ${W.skipBranchPrefixes.maxPrefixLength} characters.`)).min(1,`review.skipBranchPrefixes must contain at least one prefix.`).max(W.skipBranchPrefixes.maxItems,`review.skipBranchPrefixes must contain at most ${W.skipBranchPrefixes.maxItems} prefixes.`).describe(`Source branch prefixes that should always be skipped during review.`).optional()}).strict().superRefine((e,t)=>{e.defaultFileSliceLines!==void 0&&e.maxFileSliceLines!==void 0&&e.defaultFileSliceLines>e.maxFileSliceLines&&t.addIssue({code:p.ZodIssueCode.custom,path:[`defaultFileSliceLines`],message:`review.defaultFileSliceLines must be less than or equal to review.maxFileSliceLines.`})}),zt=p.object({$schema:p.string().max(W.schemaRefMaxLength,`$schema must be at most ${W.schemaRefMaxLength} characters.`).describe(`Optional JSON Schema reference for editor support.`).optional(),copilot:p.object({model:p.string().min(1,`copilot.model must not be empty.`).max(W.modelMaxLength,`copilot.model must be at most ${W.modelMaxLength} characters.`).describe(`Optional Copilot model override for this repository.`).optional(),reasoningEffort:p.enum(Te).describe(`Optional reasoning effort override for this repository.`).optional(),timeoutMs:Lt(`copilot.timeoutMs`,W.timeoutMs).describe(`Optional Copilot timeout in milliseconds.`).optional()}).strict().optional(),report:p.object({title:p.string().min(1,`report.title must not be empty.`).max(W.reportTitleMaxLength,`report.title must be at most ${W.reportTitleMaxLength} characters.`).describe(`Optional Code Insights report title override.`).optional(),commentStrategy:p.enum(Ee).describe(`How the tagged pull request summary comment should be updated.`).optional()}).strict().optional(),review:Rt.optional()}).strict();function Bt(e){return qe(e)}function Vt(e){return e.issues.map(e=>`${e.path.length>0?e.path.join(`.`):`config`}: ${e.message}`).join(`
|
|
11
|
+
`)}function Ht(e,t=`copilot-code-review.json`){let n;try{n=JSON.parse(e)}catch(e){throw new M(`Invalid JSON in ${t}: ${e instanceof Error?e.message:String(e)}`)}let r=zt.safeParse(n);if(r.success)return r.data;throw new M(`Invalid ${t}:\n${Vt(r.error)}`)}function Ut(e,t){return Qe(e,Je(e.internal?.envRepoOverrides??Ge(),Bt(t)))}const G=`copilot-code-review.json`;async function Wt(e,t,n,r){let i;try{let e=await t.readTextFileAtCommit(n,G);i=e.status===`ok`?e.content:void 0}catch(t){return r.warn(`Unable to read trusted repo config from ${n}:${G}`,t),e}if(i===void 0)return r.debug(`No trusted repo config found at ${n}:${G}`),e;let a=Ut(e,Ht(i,`${n}:${G}`));return a.internal={envRepoOverrides:We(e.internal?.envRepoOverrides??Ge()),trustedRepoConfig:{path:G,commit:n}},r.info(`Loaded trusted repo config from ${n}:${G}`),a}async function Gt(e,t,n,r){let i;try{let e=await t.readTextFileAtCommit(n,G);i=e.status===`ok`?e.content:void 0}catch(t){return r.warn(`Unable to read trusted repo config from ${n}:${G}`,t),e}if(i===void 0)return r.debug(`No trusted repo config found at ${n}:${G}`),e;let a=Ht(i,`${n}:${G}`),o=e.internal?.envRepoOverrides??Ge(),s=Ut({repoRoot:e.tempRoot,gitRemoteName:e.gitRemoteName,logLevel:e.logLevel,bitbucket:{...e.bitbucket,prId:1},copilot:{model:`gpt-5.4`,reasoningEffort:`xhigh`,timeoutMs:18e5},report:{key:`copilot-pr-review`,title:`Copilot PR Review`,reporter:`GitHub Copilot via Jenkins`,commentTag:`copilot-pr-review`,commentStrategy:`recreate`},review:{dryRun:e.review.dryRun,forceReview:e.review.forceReview,confirmRerun:e.review.confirmRerun,maxFiles:U.review.maxFiles,maxFindings:U.review.maxFindings,minConfidence:U.review.minConfidence,maxPatchChars:U.review.maxPatchChars,defaultFileSliceLines:U.review.defaultFileSliceLines,maxFileSliceLines:U.review.maxFileSliceLines,ignorePaths:[],skipBranchPrefixes:e.review.skipBranchPrefixes},internal:{envRepoOverrides:o}},a);return r.info(`Loaded trusted repo config from ${n}:${G}`),{...e,review:{...e.review,skipBranchPrefixes:s.review.skipBranchPrefixes}}}const Kt=m(n),qt=[`-c`,`core.quotePath=false`];function Jt(e){return e.replace(/[^A-Za-z0-9._-]+/g,`-`).replace(/-+/g,`-`).replace(/^-+|-+$/g,``)||`repo`}async function Yt(e){let t=g.resolve(e??g.join(h(),`bitbucket-copilot-pr-review`));return await i(t,{recursive:!0,mode:448}),t}async function Xt(e){let t=g.resolve(e.tempRoot),n=g.join(t,`.cache`),r=g.join(n,`${Jt(e.projectKey)}-${Jt(e.repoSlug)}`),o=g.join(r,`mirror.git`),s=await a(g.join(t,`run-`)),c=g.join(s,`workspaces`);return await i(r,{recursive:!0,mode:448}),await i(c,{recursive:!0,mode:448}),{baseRoot:t,runRoot:s,cacheRoot:n,repoRoot:c,repoCacheRoot:r,mirrorRoot:o}}async function Zt(e){try{return await l(e),!0}catch{return!1}}async function Qt(e){await i(g.dirname(e),{recursive:!0,mode:448})}async function $t(e){try{await Kt(`git`,[...qt,...e.args],{cwd:e.cwd,encoding:`utf8`,maxBuffer:32*1024*1024})}catch(t){throw e.logger.error(`Git operation failed during ${e.context}`),t}}async function en(e){let t=Date.now();for(;;)try{return await i(e,{mode:448}),async()=>{await c(e)}}catch(n){if(n.code!==`EEXIST`)throw n;if(Date.now()-t>=3e4)throw Error(`Timed out waiting for git mirror lock at ${e}.`);await new Promise(e=>setTimeout(e,200))}}async function tn(e){let t=Date.now();return{release:await en(e),lockWaitMs:Date.now()-t}}async function nn(e){let{workspace:t,cloneUrl:n,logger:r}=e;r.info(`Waiting for mirror cache lock at ${t.repoCacheRoot}`);let i=await tn(g.join(t.repoCacheRoot,`mirror.lock`)),a=Date.now();try{return await Zt(t.mirrorRoot)?(r.info(`Refreshing existing mirror cache`),await $t({cwd:t.mirrorRoot,args:[`remote`,`set-url`,`origin`,n],logger:r,context:`mirror remote update`}),await $t({cwd:t.mirrorRoot,args:[`fetch`,`--prune`,`--tags`,`origin`],logger:r,context:`mirror refresh`}),{path:t.mirrorRoot,action:`refreshed`,durationMs:Date.now()-a,lockWaitMs:i.lockWaitMs}):(r.info(`Creating mirror cache from ${n}`),await Qt(t.mirrorRoot),await $t({cwd:t.repoCacheRoot,args:[`clone`,`--mirror`,n,t.mirrorRoot],logger:r,context:`initial mirror clone`}),{path:t.mirrorRoot,action:`created`,durationMs:Date.now()-a,lockWaitMs:i.lockWaitMs})}finally{await i.release()}}async function rn(e){let t=Date.now();e.logger.info(`Creating workspace clone for PR #${e.pr.id} in ${e.workspace.repoRoot}`);let n=await a(g.join(e.workspace.repoRoot,`pr-${String(e.pr.id).padStart(6,`0`)}-`));try{await $t({cwd:e.workspace.repoRoot,args:[`clone`,`-o`,e.gitRemoteName,`--reference-if-able`,e.workspace.mirrorRoot,`--no-checkout`,e.cloneUrl,n],logger:e.logger,context:`workspace clone for PR #${e.pr.id}`});let t=new Pt(n,e.logger,e.gitRemoteName);e.logger.info(`Fetching PR #${e.pr.id} commits and checking out ${e.pr.source.latestCommit}`),await t.ensurePullRequestCommits(e.pr),await t.checkoutDetached(e.pr.source.latestCommit)}catch(e){throw await s(n,{recursive:!0,force:!0}),e}let r={provisionDurationMs:Date.now()-t,retained:!1};return{workspaceRoot:n,metrics:r,async cleanup(){e.logger.info(`Deleting workspace ${n}`);let t=Date.now();await s(n,{recursive:!0,force:!0}),r.cleanupDurationMs=Date.now()-t}}}async function an(e){if(!e.removeRoot)return 0;let t=Date.now();return await s(e.workspaceRoot,{recursive:!0,force:!0}),Date.now()-t}function on(e,t){let n=e=>`${t} ${e}`;return{debug(t,...r){e.debug(n(t),...r)},info(t,...r){e.info(n(t),...r)},warn(t,...r){e.warn(n(t),...r)},error(t,...r){e.error(n(t),...r)},trace(t,...r){e.trace(n(t),...r)},json(t){e.json(t)}}}function sn(e){return`#${e.id} ${O(e.title,80,{preserveMaxLength:!0})}`}function cn(e,n){return{...t.env,REPO_ROOT:n,GIT_REMOTE_NAME:e.gitRemoteName,LOG_LEVEL:e.logLevel,REVIEW_FORCE:e.review.forceReview?`1`:`0`,BITBUCKET_INSECURE_TLS:e.bitbucket.tls.insecureSkipVerify?`1`:`0`}}function ln(e,t,n){let r=`${e}${t}`;return r.length<=n?r:r.slice(-n)}function un(e,t){try{return JSON.parse(e)}catch(n){throw Error(`Failed to parse worker JSON output for PR #${t}: ${n instanceof Error?n.message:String(n)}\n${O(e,1200)}`)}}function dn(e){return e.skipped===!1&&(e.publicationStatus===`partial`||e.publicationStatus===`failed`)}function fn(e){return{tempRoot:e,provisioned:0,cleaned:0,retained:0,provisionDurationMsTotal:0,workspaceCleanupDurationMsTotal:0,runRootCleanupDurationMs:0,runRootRemoved:!1}}async function pn(e){let n=on(e.logger,`[${e.config.repoId}#${e.pr.id}]`),i=cn(e.config,e.workspaceRoot),a=Dt({baseUrl:e.config.bitbucket.baseUrl,projectKey:e.config.bitbucket.projectKey,repoSlug:e.config.bitbucket.repoSlug,prId:e.pr.id});e.config.bitbucket.auth.type===`bearer`?(i.BITBUCKET_AUTH_TYPE=`bearer`,i.BITBUCKET_TOKEN=e.config.bitbucket.auth.token,delete i.BITBUCKET_USERNAME,delete i.BITBUCKET_PASSWORD):(i.BITBUCKET_AUTH_TYPE=`basic`,i.BITBUCKET_USERNAME=e.config.bitbucket.auth.username,i.BITBUCKET_PASSWORD=e.config.bitbucket.auth.password,delete i.BITBUCKET_TOKEN),e.config.bitbucket.tls.caCertPath===void 0?delete i.BITBUCKET_CA_CERT_PATH:i.BITBUCKET_CA_CERT_PATH=e.config.bitbucket.tls.caCertPath;let o=t.argv[1];if(!o)throw Error(`Unable to locate the current CLI entrypoint for batch workers.`);return n.info(`Starting review worker in ${e.workspaceRoot}`),await new Promise((s,c)=>{let l=r(t.execPath,[o,`review`,a,...e.config.review.dryRun?[`--dry-run`]:[]],{cwd:t.cwd(),env:i,stdio:[`ignore`,`pipe`,`pipe`]}),u=``,d=``;l.stdout.setEncoding(`utf8`),l.stderr.setEncoding(`utf8`),l.stdout.on(`data`,e=>{u+=e}),l.stderr.on(`data`,e=>{d=ln(d,e,12e3);for(let t of e.split(/\r?\n/))t.trim().length>0&&n.info(t)}),l.on(`error`,e=>{c(e)}),l.on(`close`,t=>{try{let r=un(u,e.pr.id);t!==0&&n.warn(`Review worker exited with code ${t} but returned structured JSON output.`),n.info(`Review worker completed successfully`),s(r)}catch(n){if(t!==0){c(Error(`Review worker for PR #${e.pr.id} exited with code ${t}. ${O(d||u,4e3)}`));return}c(n)}})})}async function mn(e){let t=Date.now(),n,r=e.config,i=on(e.logger,`[${e.config.repoId}#${e.pr.id}]`);try{let a=e.loadTrustedBatchReviewConfig??Gt,o=e.pr.target.latestCommit;if(o){let t=new Pt(e.workspace.mirrorRoot,e.logger,e.config.gitRemoteName);r=await a(e.config,t,o,e.logger)}let s=It(e.pr,r.review.skipBranchPrefixes);if(s)return i.info(s),{prId:e.pr.id,title:e.pr.title,status:`skipped`,durationMs:Date.now()-t,skipReason:s};let c=e.pr.target.cloneUrl??e.pr.source.cloneUrl;if(!c)throw Error(`Pull request does not expose a usable clone URL.`);i.info(`Provisioning workspace`);let l=e.provisionPullRequestWorkspace??rn,u=e.runWorkerForPullRequest??pn;n=await l({workspace:e.workspace,pr:e.pr,cloneUrl:c,gitRemoteName:r.gitRemoteName,logger:e.logger}),n.metrics?(e.workspaceMetrics.provisioned+=1,e.workspaceMetrics.provisionDurationMsTotal+=n.metrics.provisionDurationMs,i.info(`Workspace ready at ${n.workspaceRoot} in ${n.metrics.provisionDurationMs}ms`)):i.info(`Workspace ready at ${n.workspaceRoot}`),i.info(`Running review`);let d=await u({config:r,pr:e.pr,workspaceRoot:n.workspaceRoot,logger:e.logger});return{prId:e.pr.id,title:e.pr.title,status:d.skipped?`skipped`:dn(d)?`failed`:`reviewed`,durationMs:Date.now()-t,workdir:r.keepWorkdirs?n.workspaceRoot:void 0,workspace:n.metrics,output:d,...dn(d)?{error:d.publication?.error?.message??`Review returned publication status ${d.publicationStatus}`}:{}}}catch(a){return i.error(`Review failed after ${Date.now()-t}ms: ${a instanceof Error?a.message:String(a)}`),{prId:e.pr.id,title:e.pr.title,status:`failed`,durationMs:Date.now()-t,workdir:r.keepWorkdirs?n?.workspaceRoot:void 0,workspace:n?.metrics,error:a instanceof Error?a.message:String(a)}}finally{r.keepWorkdirs&&n?.metrics&&(n.metrics.retained=!0,e.workspaceMetrics.retained+=1,i.info(`Keeping workspace at ${n.workspaceRoot}`)),!r.keepWorkdirs&&n&&(await n.cleanup(),n.metrics?(e.workspaceMetrics.cleaned+=1,e.workspaceMetrics.workspaceCleanupDurationMsTotal+=n.metrics.cleanupDurationMs??0,i.info(`Removed workspace in ${n.metrics.cleanupDurationMs??0}ms`)):i.info(`Removed workspace`))}}async function hn(e){let t=Array(e.items.length),n=0,r=async()=>{let i=n;n+=1,!(i>=e.items.length)&&(t[i]=await e.worker(e.items[i],i),await r())},i=Math.min(e.maxParallel,e.items.length);return await Promise.all(Array.from({length:i},async()=>{await r()})),t}function gn(e,t,n){return{repository:{repoId:e.repoId,projectKey:e.bitbucket.projectKey,repoSlug:e.bitbucket.repoSlug},totalOpenPullRequests:n.length,reviewed:n.filter(e=>e.status===`reviewed`).length,skipped:n.filter(e=>e.status===`skipped`).length,failed:n.filter(e=>e.status===`failed`).length,metrics:t,results:n}}async function _n(e,t,n={}){let r=n.createRepositoryClient?.(e.bitbucket)??new xe(e.bitbucket);t.info(`Loading open pull requests for ${e.bitbucket.projectKey}/${e.bitbucket.repoSlug}`);let i=await(n.resolveTempRoot??Yt)(e.tempRoot);t.info(`Using batch temp root ${i}`);let a={workspaces:fn(i)},o=await r.listOpenPullRequests();if(t.info(`Discovered ${o.length} open pull requests for ${e.bitbucket.projectKey}/${e.bitbucket.repoSlug}`),o.length===0)return t.info(`No open pull requests found; nothing to review`),gn(e,a,[]);let s=n.createWorkspace??Xt,c=n.ensureMirrorClone??nn,l=n.cleanupBatchWorkspace??an,u=await s({tempRoot:i,projectKey:e.bitbucket.projectKey,repoSlug:e.bitbucket.repoSlug});a.workspaces.runRoot=u.runRoot,t.info(`Created batch run workspace at ${u.runRoot}`);let d=o.find(e=>e.target.cloneUrl)?.target.cloneUrl??o.find(e=>e.source.cloneUrl)?.source.cloneUrl;if(!d)throw Error(`Repository ${e.repoId} does not expose a usable clone URL for batch review.`);try{t.info(`Preparing mirror cache at ${u.mirrorRoot}`),a.mirror=await c({workspace:u,cloneUrl:d,logger:t}),t.info(`Mirror cache ${a.mirror.action} in ${a.mirror.durationMs}ms (lock wait ${a.mirror.lockWaitMs}ms)`),t.info(`Starting batch review of ${o.length} pull requests with concurrency ${e.maxParallel}`);let r=0,i=await hn({items:o,maxParallel:e.maxParallel,worker:async(i,s)=>{t.info(`Starting PR ${s+1}/${o.length}: ${sn(i)}`);let c=await mn({config:e,pr:i,workspace:u,logger:t,workspaceMetrics:a.workspaces,loadTrustedBatchReviewConfig:n.loadTrustedBatchReviewConfig,provisionPullRequestWorkspace:n.provisionPullRequestWorkspace,runWorkerForPullRequest:n.runWorkerForPullRequest});return r+=1,t.info(`Finished PR ${r}/${o.length}: ${sn(i)} -> ${c.status} in ${c.durationMs}ms`),c}});return t.info(`Batch review complete: ${i.filter(e=>e.status===`reviewed`).length} reviewed, ${i.filter(e=>e.status===`skipped`).length} skipped, ${i.filter(e=>e.status===`failed`).length} failed`),gn(e,a,i)}finally{e.keepWorkdirs?t.info(`Keeping batch run workspace at ${u.runRoot}`):t.info(`Removing batch run workspace at ${u.runRoot}`),a.workspaces.runRootCleanupDurationMs=await l({workspaceRoot:u.runRoot,removeRoot:!e.keepWorkdirs}),a.workspaces.runRootRemoved=!e.keepWorkdirs,e.keepWorkdirs?t.info(`Batch run workspace retained for inspection`):t.info(`Removed batch run workspace in ${a.workspaces.runRootCleanupDurationMs}ms`)}}function vn(e,t){if(!/^\d+$/.test(t))throw new M(`${e} must be a positive integer.`);let n=Number.parseInt(t,10);if(!Number.isSafeInteger(n)||n<=0)throw new M(`${e} must be a positive integer.`);return n}function K(e,t){return t.flags.includes(e)}function yn(e){let t=e.argv[e.index+1];if(!t||t.startsWith(`-`))throw new M(`${e.flag} requires a value.`);return{value:t,nextIndex:e.index+1}}function bn(e){let t={command:`review`,pullRequestUrl:``,dryRun:!1,forceReview:!1,confirmRerun:!1,help:!1};for(let n=0;n<e.length;n+=1){let r=e[n];if(!(r===void 0||r===`--`)){if(K(r,Me.dryRun)){t.dryRun=!0;continue}if(K(r,Me.forceReview)){t.forceReview=!0;continue}if(K(r,Me.confirmRerun)){t.confirmRerun=!0;continue}if(K(r,Me.repoRoot)){let r=yn({argv:e,index:n,flag:`--repo-root`});t.repoRoot=r.value,n=r.nextIndex;continue}if(!r.startsWith(`-`)&&t.pullRequestUrl.length===0){t.pullRequestUrl=r;continue}throw new M(`Unknown argument for review: ${r}`)}}if(t.pullRequestUrl.length===0)throw new M(`review requires <pull-request-url>.`);return t}function xn(e){let t={command:`batch`,repositoryUrl:``,dryRun:!1,forceReview:!1,keepWorkdirs:!1,help:!1};for(let n=0;n<e.length;n+=1){let r=e[n];if(!(r===void 0||r===`--`)){if(K(r,R.dryRun)){t.dryRun=!0;continue}if(K(r,R.forceReview)){t.forceReview=!0;continue}if(K(r,R.tempRoot)){let r=yn({argv:e,index:n,flag:`--temp-root`});t.tempRoot=r.value,n=r.nextIndex;continue}if(K(r,R.maxParallel)){let i=yn({argv:e,index:n,flag:`--max-parallel`});t.maxParallel=vn(r,i.value),n=i.nextIndex;continue}if(K(r,R.keepWorkdirs)){t.keepWorkdirs=!0;continue}if(!r.startsWith(`-`)&&t.repositoryUrl.length===0){t.repositoryUrl=r;continue}throw new M(`Unknown argument for batch: ${r}`)}}if(t.repositoryUrl.length===0)throw new M(`batch requires <repository-url>.`);return t}function Sn(e){return e.length===1&&Me.help.flags.includes(e[0]??``)}function Cn(e){return Sn(e)}function wn(e){return e.map(e=>` ${`${e.flags.join(`, `)}${e.valueLabel?` ${e.valueLabel}`:``}`.padEnd(24)} ${e.description}`)}function Tn(){return Object.entries(je).map(([e,t])=>` ${t.usage.padEnd(34)} ${t.description}`)}function En(e){let t=je[e.commandName];return[`${e.commandName.toUpperCase()}`,` ${t.description}`,` Usage: bitbucket-copilot-pr-review ${t.usage}`,...t.argumentDescription?[` Argument: ${t.argumentLabel}`,` ${t.argumentDescription}`]:[],` Options:`,...wn(e.optionMetadata)]}function Dn(e){if(e.length===0||Sn(e))return{help:!0};let[t,...n]=e;if(t===`review`&&Cn(n))return{help:!0,commandName:`review`};if(t===`batch`&&Cn(n))return{help:!0,commandName:`batch`};if(t===`review`)return bn(n);if(t===`batch`)return xn(n);throw new M(`Unknown command: ${t}. Expected 'review' or 'batch'.`)}function On(e){return`command`in e&&e.command===`review`}function kn(e){return`command`in e&&e.command===`batch`}function An(e){return e?En({commandName:e,optionMetadata:Object.values(e===`review`?Me:R)}).join(`
|
|
12
|
+
`):[`Usage: bitbucket-copilot-pr-review <command> [options]`,``,`Commands:`,...Tn(),``,...En({commandName:`review`,optionMetadata:Object.values(Me)}),``,...En({commandName:`batch`,optionMetadata:Object.values(R)})].join(`
|
|
13
|
+
`)}function q(e){return{kind:`env`,field:e}}function jn(e){return{kind:`cliFlag`,option:e}}function J(){return{kind:`default`}}function Y(e,t,n={}){return n.transform===void 0?{field:e,sources:t}:{field:e,sources:t,transform:n.transform}}const Mn=[Y(`bitbucketInsecureTls`,[q(`bitbucketInsecureTls`),J()]),Y(`copilotModel`,[q(`copilotModel`),J()]),Y(`copilotReasoningEffort`,[q(`copilotReasoningEffort`),J()]),Y(`copilotTimeoutMs`,[q(`copilotTimeoutMs`),J()]),Y(`reportKey`,[q(`reportKey`),J()],{transform:`normalizeReportKey`}),Y(`reportTitle`,[q(`reportTitle`),J()]),Y(`reporterName`,[q(`reporterName`),J()]),Y(`reportCommentTag`,[q(`reportCommentTag`),J()]),Y(`reportCommentStrategy`,[q(`reportCommentStrategy`),J()]),Y(`reportLink`,[q(`reportLink`),q(`buildUrl`)]),Y(`reviewDryRun`,[jn(`dryRun`),J()]),Y(`reviewForce`,[jn(`forceReview`),q(`reviewForce`),J()]),Y(`reviewConfirmRerun`,[jn(`confirmRerun`),J()]),Y(`reviewMaxFiles`,[q(`reviewMaxFiles`),J()]),Y(`reviewMaxFindings`,[q(`reviewMaxFindings`),J()]),Y(`reviewMinConfidence`,[q(`reviewMinConfidence`),J()]),Y(`reviewMaxPatchChars`,[q(`reviewMaxPatchChars`),J()]),Y(`reviewDefaultFileSliceLines`,[q(`reviewDefaultFileSliceLines`),J()]),Y(`reviewMaxFileSliceLines`,[q(`reviewMaxFileSliceLines`),J()]),Y(`reviewIgnorePaths`,[q(`reviewIgnorePaths`),J()]),Y(`reviewSkipBranchPrefixes`,[q(`reviewSkipBranchPrefixes`),J()])],Nn={repoRoot:(e,t)=>zn(t.repoRoot,e.REPO_ROOT),gitRemoteName:e=>e.GIT_REMOTE_NAME??U.gitRemoteName,logLevel:e=>e.LOG_LEVEL??U.logLevel,ciSummaryPath:e=>e.CI_SUMMARY_PATH};function Pn(e){return V(U,z(Ae[e].path))}function Fn(e,t){let n=Ae[t];if(!(`env`in n)||n.env===void 0)throw Error(`Runtime env source ${String(t)} is missing an env key.`);return e[n.env]}function In(e,t,n,r){switch(r.kind){case`env`:return Fn(e,r.field);case`cliFlag`:return t[r.option]?!0:void 0;case`default`:return Pn(n.field)}}function Ln(e,t){if(t.transform===`normalizeReportKey`){if(typeof e!=`string`)throw Error(`normalizeReportKey requires a string value for ${String(t.field)}.`);return ht(e)}return e}function Rn(e){let t=e=>typeof e==`boolean`,n=e=>typeof e==`string`,r=e=>typeof e==`number`,i=e=>Array.isArray(e)&&e.every(e=>typeof e==`string`),a=e.bitbucket.tls;if(!t(a?.insecureSkipVerify))throw Error(`Runtime resolver did not produce bitbucket.tls.insecureSkipVerify.`);if(!n(e.copilot.model)||!n(e.copilot.reasoningEffort)||!r(e.copilot.timeoutMs))throw Error(`Runtime resolver did not produce a complete copilot config.`);if(!n(e.report.key)||!n(e.report.title)||!n(e.report.reporter)||!n(e.report.commentTag)||!n(e.report.commentStrategy))throw Error(`Runtime resolver did not produce a complete report config.`);if(!t(e.review.dryRun)||!t(e.review.forceReview)||!t(e.review.confirmRerun)||!r(e.review.maxFiles)||!r(e.review.maxFindings)||!n(e.review.minConfidence)||!r(e.review.maxPatchChars)||!r(e.review.defaultFileSliceLines)||!r(e.review.maxFileSliceLines)||!i(e.review.ignorePaths)||!i(e.review.skipBranchPrefixes))throw Error(`Runtime resolver did not produce a complete review config.`)}function zn(e,t){let n=e??t??process.cwd(),r=g.resolve(n);try{ee(r,te.R_OK)}catch{throw new M(`Repository root is not readable: ${r}`)}return r}function Bn(e,t){let n=Nn.repoRoot(e,t),r=Nn.gitRemoteName(e,t),i=Nn.logLevel(e,t),a=Nn.ciSummaryPath(e,t);return{repoRoot:n,gitRemoteName:r,logLevel:i,...a===void 0?{}:{ciSummaryPath:a}}}function Vn(e,t){let n={bitbucket:{},copilot:{},report:{},review:{}};for(let r of Mn){let i;for(let n of r.sources){let a=In(e,t,r,n);if(a!==void 0){i=Ln(a,r);break}}if(i===void 0)continue;let[a,...o]=z(Ae[r.field].path);if(a===void 0||a!==`bitbucket`&&a!==`copilot`&&a!==`report`&&a!==`review`)throw Error(`Runtime resolver field ${String(r.field)} must target bitbucket, copilot, report, or review.`);Ie(n[a],o,i)}return Rn(n),{...Bn(e,t),bitbucket:n.bitbucket,copilot:n.copilot,report:n.report,review:n.review}}function Hn(e,t){let n=g.resolve(e);try{ee(n,te.R_OK)}catch{throw new M(`${t} is not readable: ${n}`)}return n}function Un(e=process.argv.slice(2),t=process.env,n=(()=>{let t=Dn(e[0]===`review`?e:[`review`,...e]);if(!On(t))throw new M(`review command options are required.`);return t})()){let r=Et(n.pullRequestUrl),i=yt(t),a=gt(i),o=Vn(i,n),s=i.BITBUCKET_CA_CERT_PATH===void 0?void 0:Hn(i.BITBUCKET_CA_CERT_PATH,`BITBUCKET_CA_CERT_PATH`);return Ze({repoRoot:o.repoRoot,gitRemoteName:o.gitRemoteName,logLevel:o.logLevel,bitbucket:kt({location:r,env:i,runtimeConfig:o.bitbucket,...s===void 0?{}:{caCertPath:s}}),copilot:w(o.copilot),report:w(o.report),review:o.review,...o.ciSummaryPath===void 0?{}:{ciSummaryPath:o.ciSummaryPath},internal:{envRepoOverrides:We(a)}})}function Wn(e=process.argv.slice(2),t=process.env,n=(()=>{let t=Dn(e[0]===`batch`?e:[`batch`,...e]);if(!kn(t))throw new M(`batch command options are required.`);return t})()){let r=yt(t),i=Tt(n.repositoryUrl),a=r.BITBUCKET_CA_CERT_PATH===void 0?void 0:Hn(r.BITBUCKET_CA_CERT_PATH,`BITBUCKET_CA_CERT_PATH`),o=n.tempRoot===void 0?g.join(h(),`bitbucket-copilot-pr-review`):g.resolve(n.tempRoot);return{repoId:`${i.projectKey}/${i.repoSlug}`,repositoryUrl:i.repositoryUrl,tempRoot:o,maxParallel:n.maxParallel??2,keepWorkdirs:n.keepWorkdirs??!1,gitRemoteName:r.GIT_REMOTE_NAME??U.gitRemoteName,logLevel:r.LOG_LEVEL??U.logLevel,bitbucket:{baseUrl:i.baseUrl,projectKey:i.projectKey,repoSlug:i.repoSlug,auth:Ot(r),tls:w({caCertPath:a,insecureSkipVerify:r.BITBUCKET_INSECURE_TLS??U.bitbucket.tls.insecureSkipVerify})},review:{dryRun:n.dryRun,forceReview:n.forceReview||r.REVIEW_FORCE||U.review.forceReview,confirmRerun:U.review.confirmRerun,skipBranchPrefixes:r.REVIEW_SKIP_BRANCH_PREFIXES??U.review.skipBranchPrefixes},internal:{envRepoOverrides:We(gt(r))}}}var Gn=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.stringArray=e.array=e.func=e.error=e.number=e.string=e.boolean=void 0;function t(e){return e===!0||e===!1}e.boolean=t;function n(e){return typeof e==`string`||e instanceof String}e.string=n;function r(e){return typeof e==`number`||e instanceof Number}e.number=r;function i(e){return e instanceof Error}e.error=i;function a(e){return typeof e==`function`}e.func=a;function o(e){return Array.isArray(e)}e.array=o;function s(e){return o(e)&&e.every(e=>n(e))}e.stringArray=s})),Kn=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.Message=e.NotificationType9=e.NotificationType8=e.NotificationType7=e.NotificationType6=e.NotificationType5=e.NotificationType4=e.NotificationType3=e.NotificationType2=e.NotificationType1=e.NotificationType0=e.NotificationType=e.RequestType9=e.RequestType8=e.RequestType7=e.RequestType6=e.RequestType5=e.RequestType4=e.RequestType3=e.RequestType2=e.RequestType1=e.RequestType=e.RequestType0=e.AbstractMessageSignature=e.ParameterStructures=e.ResponseError=e.ErrorCodes=void 0;let t=Gn();var n;(function(e){e.ParseError=-32700,e.InvalidRequest=-32600,e.MethodNotFound=-32601,e.InvalidParams=-32602,e.InternalError=-32603,e.jsonrpcReservedErrorRangeStart=-32099,e.serverErrorStart=-32099,e.MessageWriteError=-32099,e.MessageReadError=-32098,e.PendingResponseRejected=-32097,e.ConnectionInactive=-32096,e.ServerNotInitialized=-32002,e.UnknownErrorCode=-32001,e.jsonrpcReservedErrorRangeEnd=-32e3,e.serverErrorEnd=-32e3})(n||(e.ErrorCodes=n={})),e.ResponseError=class e extends Error{constructor(r,i,a){super(i),this.code=t.number(r)?r:n.UnknownErrorCode,this.data=a,Object.setPrototypeOf(this,e.prototype)}toJson(){let e={code:this.code,message:this.message};return this.data!==void 0&&(e.data=this.data),e}};var r=class e{constructor(e){this.kind=e}static is(t){return t===e.auto||t===e.byName||t===e.byPosition}toString(){return this.kind}};e.ParameterStructures=r,r.auto=new r(`auto`),r.byPosition=new r(`byPosition`),r.byName=new r(`byName`);var i=class{constructor(e,t){this.method=e,this.numberOfParams=t}get parameterStructures(){return r.auto}};e.AbstractMessageSignature=i,e.RequestType0=class extends i{constructor(e){super(e,0)}},e.RequestType=class extends i{constructor(e,t=r.auto){super(e,1),this._parameterStructures=t}get parameterStructures(){return this._parameterStructures}},e.RequestType1=class extends i{constructor(e,t=r.auto){super(e,1),this._parameterStructures=t}get parameterStructures(){return this._parameterStructures}},e.RequestType2=class extends i{constructor(e){super(e,2)}},e.RequestType3=class extends i{constructor(e){super(e,3)}},e.RequestType4=class extends i{constructor(e){super(e,4)}},e.RequestType5=class extends i{constructor(e){super(e,5)}},e.RequestType6=class extends i{constructor(e){super(e,6)}},e.RequestType7=class extends i{constructor(e){super(e,7)}},e.RequestType8=class extends i{constructor(e){super(e,8)}},e.RequestType9=class extends i{constructor(e){super(e,9)}},e.NotificationType=class extends i{constructor(e,t=r.auto){super(e,1),this._parameterStructures=t}get parameterStructures(){return this._parameterStructures}},e.NotificationType0=class extends i{constructor(e){super(e,0)}},e.NotificationType1=class extends i{constructor(e,t=r.auto){super(e,1),this._parameterStructures=t}get parameterStructures(){return this._parameterStructures}},e.NotificationType2=class extends i{constructor(e){super(e,2)}},e.NotificationType3=class extends i{constructor(e){super(e,3)}},e.NotificationType4=class extends i{constructor(e){super(e,4)}},e.NotificationType5=class extends i{constructor(e){super(e,5)}},e.NotificationType6=class extends i{constructor(e){super(e,6)}},e.NotificationType7=class extends i{constructor(e){super(e,7)}},e.NotificationType8=class extends i{constructor(e){super(e,8)}},e.NotificationType9=class extends i{constructor(e){super(e,9)}};var a;(function(e){function n(e){let n=e;return n&&t.string(n.method)&&(t.string(n.id)||t.number(n.id))}e.isRequest=n;function r(e){let n=e;return n&&t.string(n.method)&&e.id===void 0}e.isNotification=r;function i(e){let n=e;return n&&(n.result!==void 0||!!n.error)&&(t.string(n.id)||t.number(n.id)||n.id===null)}e.isResponse=i})(a||(e.Message=a={}))})),qn=S((e=>{var t;Object.defineProperty(e,`__esModule`,{value:!0}),e.LRUCache=e.LinkedMap=e.Touch=void 0;var n;(function(e){e.None=0,e.First=1,e.AsOld=e.First,e.Last=2,e.AsNew=e.Last})(n||(e.Touch=n={}));var r=class{constructor(){this[t]=`LinkedMap`,this._map=new Map,this._head=void 0,this._tail=void 0,this._size=0,this._state=0}clear(){this._map.clear(),this._head=void 0,this._tail=void 0,this._size=0,this._state++}isEmpty(){return!this._head&&!this._tail}get size(){return this._size}get first(){return this._head?.value}get last(){return this._tail?.value}has(e){return this._map.has(e)}get(e,t=n.None){let r=this._map.get(e);if(r)return t!==n.None&&this.touch(r,t),r.value}set(e,t,r=n.None){let i=this._map.get(e);if(i)i.value=t,r!==n.None&&this.touch(i,r);else{switch(i={key:e,value:t,next:void 0,previous:void 0},r){case n.None:this.addItemLast(i);break;case n.First:this.addItemFirst(i);break;case n.Last:this.addItemLast(i);break;default:this.addItemLast(i);break}this._map.set(e,i),this._size++}return this}delete(e){return!!this.remove(e)}remove(e){let t=this._map.get(e);if(t)return this._map.delete(e),this.removeItem(t),this._size--,t.value}shift(){if(!this._head&&!this._tail)return;if(!this._head||!this._tail)throw Error(`Invalid list`);let e=this._head;return this._map.delete(e.key),this.removeItem(e),this._size--,e.value}forEach(e,t){let n=this._state,r=this._head;for(;r;){if(t?e.bind(t)(r.value,r.key,this):e(r.value,r.key,this),this._state!==n)throw Error(`LinkedMap got modified during iteration.`);r=r.next}}keys(){let e=this._state,t=this._head,n={[Symbol.iterator]:()=>n,next:()=>{if(this._state!==e)throw Error(`LinkedMap got modified during iteration.`);if(t){let e={value:t.key,done:!1};return t=t.next,e}else return{value:void 0,done:!0}}};return n}values(){let e=this._state,t=this._head,n={[Symbol.iterator]:()=>n,next:()=>{if(this._state!==e)throw Error(`LinkedMap got modified during iteration.`);if(t){let e={value:t.value,done:!1};return t=t.next,e}else return{value:void 0,done:!0}}};return n}entries(){let e=this._state,t=this._head,n={[Symbol.iterator]:()=>n,next:()=>{if(this._state!==e)throw Error(`LinkedMap got modified during iteration.`);if(t){let e={value:[t.key,t.value],done:!1};return t=t.next,e}else return{value:void 0,done:!0}}};return n}[(t=Symbol.toStringTag,Symbol.iterator)](){return this.entries()}trimOld(e){if(e>=this.size)return;if(e===0){this.clear();return}let t=this._head,n=this.size;for(;t&&n>e;)this._map.delete(t.key),t=t.next,n--;this._head=t,this._size=n,t&&(t.previous=void 0),this._state++}addItemFirst(e){if(!this._head&&!this._tail)this._tail=e;else if(this._head)e.next=this._head,this._head.previous=e;else throw Error(`Invalid list`);this._head=e,this._state++}addItemLast(e){if(!this._head&&!this._tail)this._head=e;else if(this._tail)e.previous=this._tail,this._tail.next=e;else throw Error(`Invalid list`);this._tail=e,this._state++}removeItem(e){if(e===this._head&&e===this._tail)this._head=void 0,this._tail=void 0;else if(e===this._head){if(!e.next)throw Error(`Invalid list`);e.next.previous=void 0,this._head=e.next}else if(e===this._tail){if(!e.previous)throw Error(`Invalid list`);e.previous.next=void 0,this._tail=e.previous}else{let t=e.next,n=e.previous;if(!t||!n)throw Error(`Invalid list`);t.previous=n,n.next=t}e.next=void 0,e.previous=void 0,this._state++}touch(e,t){if(!this._head||!this._tail)throw Error(`Invalid list`);if(!(t!==n.First&&t!==n.Last)){if(t===n.First){if(e===this._head)return;let t=e.next,n=e.previous;e===this._tail?(n.next=void 0,this._tail=n):(t.previous=n,n.next=t),e.previous=void 0,e.next=this._head,this._head.previous=e,this._head=e,this._state++}else if(t===n.Last){if(e===this._tail)return;let t=e.next,n=e.previous;e===this._head?(t.previous=void 0,this._head=t):(t.previous=n,n.next=t),e.next=void 0,e.previous=this._tail,this._tail.next=e,this._tail=e,this._state++}}}toJSON(){let e=[];return this.forEach((t,n)=>{e.push([n,t])}),e}fromJSON(e){this.clear();for(let[t,n]of e)this.set(t,n)}};e.LinkedMap=r,e.LRUCache=class extends r{constructor(e,t=1){super(),this._limit=e,this._ratio=Math.min(Math.max(0,t),1)}get limit(){return this._limit}set limit(e){this._limit=e,this.checkTrim()}get ratio(){return this._ratio}set ratio(e){this._ratio=Math.min(Math.max(0,e),1),this.checkTrim()}get(e,t=n.AsNew){return super.get(e,t)}peek(e){return super.get(e,n.None)}set(e,t){return super.set(e,t,n.Last),this.checkTrim(),this}checkTrim(){this.size>this._limit&&this.trimOld(Math.round(this._limit*this._ratio))}}})),Jn=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.Disposable=void 0;var t;(function(e){function t(e){return{dispose:e}}e.create=t})(t||(e.Disposable=t={}))})),Yn=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0});let t;function n(){if(t===void 0)throw Error(`No runtime abstraction layer installed`);return t}(function(e){function n(e){if(e===void 0)throw Error(`No runtime abstraction layer provided`);t=e}e.install=n})(n||={}),e.default=n})),Xn=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.Emitter=e.Event=void 0;let t=Yn();var n;(function(e){let t={dispose(){}};e.None=function(){return t}})(n||(e.Event=n={}));var r=class{add(e,t=null,n){this._callbacks||(this._callbacks=[],this._contexts=[]),this._callbacks.push(e),this._contexts.push(t),Array.isArray(n)&&n.push({dispose:()=>this.remove(e,t)})}remove(e,t=null){if(!this._callbacks)return;let n=!1;for(let r=0,i=this._callbacks.length;r<i;r++)if(this._callbacks[r]===e)if(this._contexts[r]===t){this._callbacks.splice(r,1),this._contexts.splice(r,1);return}else n=!0;if(n)throw Error(`When adding a listener with a context, you should remove it with the same context`)}invoke(...e){if(!this._callbacks)return[];let n=[],r=this._callbacks.slice(0),i=this._contexts.slice(0);for(let a=0,o=r.length;a<o;a++)try{n.push(r[a].apply(i[a],e))}catch(e){(0,t.default)().console.error(e)}return n}isEmpty(){return!this._callbacks||this._callbacks.length===0}dispose(){this._callbacks=void 0,this._contexts=void 0}},i=class e{constructor(e){this._options=e}get event(){return this._event||=(t,n,i)=>{this._callbacks||=new r,this._options&&this._options.onFirstListenerAdd&&this._callbacks.isEmpty()&&this._options.onFirstListenerAdd(this),this._callbacks.add(t,n);let a={dispose:()=>{this._callbacks&&(this._callbacks.remove(t,n),a.dispose=e._noop,this._options&&this._options.onLastListenerRemove&&this._callbacks.isEmpty()&&this._options.onLastListenerRemove(this))}};return Array.isArray(i)&&i.push(a),a},this._event}fire(e){this._callbacks&&this._callbacks.invoke.call(this._callbacks,e)}dispose(){this._callbacks&&=(this._callbacks.dispose(),void 0)}};e.Emitter=i,i._noop=function(){}})),Zn=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.CancellationTokenSource=e.CancellationToken=void 0;let t=Yn(),n=Gn(),r=Xn();var i;(function(e){e.None=Object.freeze({isCancellationRequested:!1,onCancellationRequested:r.Event.None}),e.Cancelled=Object.freeze({isCancellationRequested:!0,onCancellationRequested:r.Event.None});function t(t){let r=t;return r&&(r===e.None||r===e.Cancelled||n.boolean(r.isCancellationRequested)&&!!r.onCancellationRequested)}e.is=t})(i||(e.CancellationToken=i={}));let a=Object.freeze(function(e,n){let r=(0,t.default)().timer.setTimeout(e.bind(n),0);return{dispose(){r.dispose()}}});var o=class{constructor(){this._isCancelled=!1}cancel(){this._isCancelled||(this._isCancelled=!0,this._emitter&&(this._emitter.fire(void 0),this.dispose()))}get isCancellationRequested(){return this._isCancelled}get onCancellationRequested(){return this._isCancelled?a:(this._emitter||=new r.Emitter,this._emitter.event)}dispose(){this._emitter&&=(this._emitter.dispose(),void 0)}};e.CancellationTokenSource=class{get token(){return this._token||=new o,this._token}cancel(){this._token?this._token.cancel():this._token=i.Cancelled}dispose(){this._token?this._token instanceof o&&this._token.dispose():this._token=i.None}}})),Qn=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.SharedArrayReceiverStrategy=e.SharedArraySenderStrategy=void 0;let t=Zn();var n;(function(e){e.Continue=0,e.Cancelled=1})(n||={}),e.SharedArraySenderStrategy=class{constructor(){this.buffers=new Map}enableCancellation(e){if(e.id===null)return;let t=new SharedArrayBuffer(4),r=new Int32Array(t,0,1);r[0]=n.Continue,this.buffers.set(e.id,t),e.$cancellationData=t}async sendCancellation(e,t){let r=this.buffers.get(t);if(r===void 0)return;let i=new Int32Array(r,0,1);Atomics.store(i,0,n.Cancelled)}cleanup(e){this.buffers.delete(e)}dispose(){this.buffers.clear()}};var r=class{constructor(e){this.data=new Int32Array(e,0,1)}get isCancellationRequested(){return Atomics.load(this.data,0)===n.Cancelled}get onCancellationRequested(){throw Error(`Cancellation over SharedArrayBuffer doesn't support cancellation events`)}},i=class{constructor(e){this.token=new r(e)}cancel(){}dispose(){}};e.SharedArrayReceiverStrategy=class{constructor(){this.kind=`request`}createCancellationTokenSource(e){let n=e.$cancellationData;return n===void 0?new t.CancellationTokenSource:new i(n)}}})),$n=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.Semaphore=void 0;let t=Yn();e.Semaphore=class{constructor(e=1){if(e<=0)throw Error(`Capacity must be greater than 0`);this._capacity=e,this._active=0,this._waiting=[]}lock(e){return new Promise((t,n)=>{this._waiting.push({thunk:e,resolve:t,reject:n}),this.runNext()})}get active(){return this._active}runNext(){this._waiting.length===0||this._active===this._capacity||(0,t.default)().timer.setImmediate(()=>this.doRunNext())}doRunNext(){if(this._waiting.length===0||this._active===this._capacity)return;let e=this._waiting.shift();if(this._active++,this._active>this._capacity)throw Error(`To many thunks active`);try{let t=e.thunk();t instanceof Promise?t.then(t=>{this._active--,e.resolve(t),this.runNext()},t=>{this._active--,e.reject(t),this.runNext()}):(this._active--,e.resolve(t),this.runNext())}catch(t){this._active--,e.reject(t),this.runNext()}}}})),er=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.ReadableStreamMessageReader=e.AbstractMessageReader=e.MessageReader=void 0;let t=Yn(),n=Gn(),r=Xn(),i=$n();var a;(function(e){function t(e){let t=e;return t&&n.func(t.listen)&&n.func(t.dispose)&&n.func(t.onError)&&n.func(t.onClose)&&n.func(t.onPartialMessage)}e.is=t})(a||(e.MessageReader=a={}));var o=class{constructor(){this.errorEmitter=new r.Emitter,this.closeEmitter=new r.Emitter,this.partialMessageEmitter=new r.Emitter}dispose(){this.errorEmitter.dispose(),this.closeEmitter.dispose()}get onError(){return this.errorEmitter.event}fireError(e){this.errorEmitter.fire(this.asError(e))}get onClose(){return this.closeEmitter.event}fireClose(){this.closeEmitter.fire(void 0)}get onPartialMessage(){return this.partialMessageEmitter.event}firePartialMessage(e){this.partialMessageEmitter.fire(e)}asError(e){return e instanceof Error?e:Error(`Reader received error. Reason: ${n.string(e.message)?e.message:`unknown`}`)}};e.AbstractMessageReader=o;var s;(function(e){function n(e){let n,r,i=new Map,a,o=new Map;if(e===void 0||typeof e==`string`)n=e??`utf-8`;else{if(n=e.charset??`utf-8`,e.contentDecoder!==void 0&&(r=e.contentDecoder,i.set(r.name,r)),e.contentDecoders!==void 0)for(let t of e.contentDecoders)i.set(t.name,t);if(e.contentTypeDecoder!==void 0&&(a=e.contentTypeDecoder,o.set(a.name,a)),e.contentTypeDecoders!==void 0)for(let t of e.contentTypeDecoders)o.set(t.name,t)}return a===void 0&&(a=(0,t.default)().applicationJson.decoder,o.set(a.name,a)),{charset:n,contentDecoder:r,contentDecoders:i,contentTypeDecoder:a,contentTypeDecoders:o}}e.fromOptions=n})(s||={}),e.ReadableStreamMessageReader=class extends o{constructor(e,n){super(),this.readable=e,this.options=s.fromOptions(n),this.buffer=(0,t.default)().messageBuffer.create(this.options.charset),this._partialMessageTimeout=1e4,this.nextMessageLength=-1,this.messageToken=0,this.readSemaphore=new i.Semaphore(1)}set partialMessageTimeout(e){this._partialMessageTimeout=e}get partialMessageTimeout(){return this._partialMessageTimeout}listen(e){this.nextMessageLength=-1,this.messageToken=0,this.partialMessageTimer=void 0,this.callback=e;let t=this.readable.onData(e=>{this.onData(e)});return this.readable.onError(e=>this.fireError(e)),this.readable.onClose(()=>this.fireClose()),t}onData(e){try{for(this.buffer.append(e);;){if(this.nextMessageLength===-1){let e=this.buffer.tryReadHeaders(!0);if(!e)return;let t=e.get(`content-length`);if(!t){this.fireError(Error(`Header must provide a Content-Length property.\n${JSON.stringify(Object.fromEntries(e))}`));return}let n=parseInt(t);if(isNaN(n)){this.fireError(Error(`Content-Length value must be a number. Got ${t}`));return}this.nextMessageLength=n}let e=this.buffer.tryReadBody(this.nextMessageLength);if(e===void 0){this.setPartialMessageTimer();return}this.clearPartialMessageTimer(),this.nextMessageLength=-1,this.readSemaphore.lock(async()=>{let t=this.options.contentDecoder===void 0?e:await this.options.contentDecoder.decode(e),n=await this.options.contentTypeDecoder.decode(t,this.options);this.callback(n)}).catch(e=>{this.fireError(e)})}}catch(e){this.fireError(e)}}clearPartialMessageTimer(){this.partialMessageTimer&&=(this.partialMessageTimer.dispose(),void 0)}setPartialMessageTimer(){this.clearPartialMessageTimer(),!(this._partialMessageTimeout<=0)&&(this.partialMessageTimer=(0,t.default)().timer.setTimeout((e,t)=>{this.partialMessageTimer=void 0,e===this.messageToken&&(this.firePartialMessage({messageToken:e,waitingTime:t}),this.setPartialMessageTimer())},this._partialMessageTimeout,this.messageToken,this._partialMessageTimeout))}}})),tr=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.WriteableStreamMessageWriter=e.AbstractMessageWriter=e.MessageWriter=void 0;let t=Yn(),n=Gn(),r=$n(),i=Xn();var a;(function(e){function t(e){let t=e;return t&&n.func(t.dispose)&&n.func(t.onClose)&&n.func(t.onError)&&n.func(t.write)}e.is=t})(a||(e.MessageWriter=a={}));var o=class{constructor(){this.errorEmitter=new i.Emitter,this.closeEmitter=new i.Emitter}dispose(){this.errorEmitter.dispose(),this.closeEmitter.dispose()}get onError(){return this.errorEmitter.event}fireError(e,t,n){this.errorEmitter.fire([this.asError(e),t,n])}get onClose(){return this.closeEmitter.event}fireClose(){this.closeEmitter.fire(void 0)}asError(e){return e instanceof Error?e:Error(`Writer received error. Reason: ${n.string(e.message)?e.message:`unknown`}`)}};e.AbstractMessageWriter=o;var s;(function(e){function n(e){return e===void 0||typeof e==`string`?{charset:e??`utf-8`,contentTypeEncoder:(0,t.default)().applicationJson.encoder}:{charset:e.charset??`utf-8`,contentEncoder:e.contentEncoder,contentTypeEncoder:e.contentTypeEncoder??(0,t.default)().applicationJson.encoder}}e.fromOptions=n})(s||={}),e.WriteableStreamMessageWriter=class extends o{constructor(e,t){super(),this.writable=e,this.options=s.fromOptions(t),this.errorCount=0,this.writeSemaphore=new r.Semaphore(1),this.writable.onError(e=>this.fireError(e)),this.writable.onClose(()=>this.fireClose())}async write(e){return this.writeSemaphore.lock(async()=>this.options.contentTypeEncoder.encode(e,this.options).then(e=>this.options.contentEncoder===void 0?e:this.options.contentEncoder.encode(e)).then(t=>{let n=[];return n.push(`Content-Length: `,t.byteLength.toString(),`\r
|
|
14
|
+
`),n.push(`\r
|
|
15
|
+
`),this.doWrite(e,n,t)},e=>{throw this.fireError(e),e}))}async doWrite(e,t,n){try{return await this.writable.write(t.join(``),`ascii`),this.writable.write(n)}catch(t){return this.handleError(t,e),Promise.reject(t)}}handleError(e,t){this.errorCount++,this.fireError(e,t,this.errorCount)}end(){this.writable.end()}}})),nr=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.AbstractMessageBuffer=void 0,e.AbstractMessageBuffer=class{constructor(e=`utf-8`){this._encoding=e,this._chunks=[],this._totalLength=0}get encoding(){return this._encoding}append(e){let t=typeof e==`string`?this.fromString(e,this._encoding):e;this._chunks.push(t),this._totalLength+=t.byteLength}tryReadHeaders(e=!1){if(this._chunks.length===0)return;let t=0,n=0,r=0,i=0;row:for(;n<this._chunks.length;){let e=this._chunks[n];r=0;column:for(;r<e.length;){switch(e[r]){case 13:switch(t){case 0:t=1;break;case 2:t=3;break;default:t=0}break;case 10:switch(t){case 1:t=2;break;case 3:t=4,r++;break row;default:t=0}break;default:t=0}r++}i+=e.byteLength,n++}if(t!==4)return;let a=this._read(i+r),o=new Map,s=this.toString(a,`ascii`).split(`\r
|
|
16
|
+
`);if(s.length<2)return o;for(let t=0;t<s.length-2;t++){let n=s[t],r=n.indexOf(`:`);if(r===-1)throw Error(`Message header must separate key and value using ':'\n${n}`);let i=n.substr(0,r),a=n.substr(r+1).trim();o.set(e?i.toLowerCase():i,a)}return o}tryReadBody(e){if(!(this._totalLength<e))return this._read(e)}get numberOfBytes(){return this._totalLength}_read(e){if(e===0)return this.emptyBuffer();if(e>this._totalLength)throw Error(`Cannot read so many bytes!`);if(this._chunks[0].byteLength===e){let t=this._chunks[0];return this._chunks.shift(),this._totalLength-=e,this.asNative(t)}if(this._chunks[0].byteLength>e){let t=this._chunks[0],n=this.asNative(t,e);return this._chunks[0]=t.slice(e),this._totalLength-=e,n}let t=this.allocNative(e),n=0;for(;e>0;){let r=this._chunks[0];if(r.byteLength>e){let i=r.slice(0,e);t.set(i,n),n+=e,this._chunks[0]=r.slice(e),this._totalLength-=e,e-=e}else t.set(r,n),n+=r.byteLength,this._chunks.shift(),this._totalLength-=r.byteLength,e-=r.byteLength}return t}}})),rr=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.createMessageConnection=e.ConnectionOptions=e.MessageStrategy=e.CancellationStrategy=e.CancellationSenderStrategy=e.CancellationReceiverStrategy=e.RequestCancellationReceiverStrategy=e.IdCancellationReceiverStrategy=e.ConnectionStrategy=e.ConnectionError=e.ConnectionErrors=e.LogTraceNotification=e.SetTraceNotification=e.TraceFormat=e.TraceValues=e.Trace=e.NullLogger=e.ProgressType=e.ProgressToken=void 0;let t=Yn(),n=Gn(),r=Kn(),i=qn(),a=Xn(),o=Zn();var s;(function(e){e.type=new r.NotificationType(`$/cancelRequest`)})(s||={});var c;(function(e){function t(e){return typeof e==`string`||typeof e==`number`}e.is=t})(c||(e.ProgressToken=c={}));var l;(function(e){e.type=new r.NotificationType(`$/progress`)})(l||={}),e.ProgressType=class{constructor(){}};var u;(function(e){function t(e){return n.func(e)}e.is=t})(u||={}),e.NullLogger=Object.freeze({error:()=>{},warn:()=>{},info:()=>{},log:()=>{}});var d;(function(e){e[e.Off=0]=`Off`,e[e.Messages=1]=`Messages`,e[e.Compact=2]=`Compact`,e[e.Verbose=3]=`Verbose`})(d||(e.Trace=d={}));var f;(function(e){e.Off=`off`,e.Messages=`messages`,e.Compact=`compact`,e.Verbose=`verbose`})(f||(e.TraceValues=f={})),(function(e){function t(t){if(!n.string(t))return e.Off;switch(t=t.toLowerCase(),t){case`off`:return e.Off;case`messages`:return e.Messages;case`compact`:return e.Compact;case`verbose`:return e.Verbose;default:return e.Off}}e.fromString=t;function r(t){switch(t){case e.Off:return`off`;case e.Messages:return`messages`;case e.Compact:return`compact`;case e.Verbose:return`verbose`;default:return`off`}}e.toString=r})(d||(e.Trace=d={}));var p;(function(e){e.Text=`text`,e.JSON=`json`})(p||(e.TraceFormat=p={})),(function(e){function t(t){return n.string(t)?(t=t.toLowerCase(),t===`json`?e.JSON:e.Text):e.Text}e.fromString=t})(p||(e.TraceFormat=p={}));var m;(function(e){e.type=new r.NotificationType(`$/setTrace`)})(m||(e.SetTraceNotification=m={}));var h;(function(e){e.type=new r.NotificationType(`$/logTrace`)})(h||(e.LogTraceNotification=h={}));var g;(function(e){e[e.Closed=1]=`Closed`,e[e.Disposed=2]=`Disposed`,e[e.AlreadyListening=3]=`AlreadyListening`})(g||(e.ConnectionErrors=g={}));var _=class e extends Error{constructor(t,n){super(n),this.code=t,Object.setPrototypeOf(this,e.prototype)}};e.ConnectionError=_;var v;(function(e){function t(e){let t=e;return t&&n.func(t.cancelUndispatched)}e.is=t})(v||(e.ConnectionStrategy=v={}));var ee;(function(e){function t(e){let t=e;return t&&(t.kind===void 0||t.kind===`id`)&&n.func(t.createCancellationTokenSource)&&(t.dispose===void 0||n.func(t.dispose))}e.is=t})(ee||(e.IdCancellationReceiverStrategy=ee={}));var te;(function(e){function t(e){let t=e;return t&&t.kind===`request`&&n.func(t.createCancellationTokenSource)&&(t.dispose===void 0||n.func(t.dispose))}e.is=t})(te||(e.RequestCancellationReceiverStrategy=te={}));var y;(function(e){e.Message=Object.freeze({createCancellationTokenSource(e){return new o.CancellationTokenSource}});function t(e){return ee.is(e)||te.is(e)}e.is=t})(y||(e.CancellationReceiverStrategy=y={}));var b;(function(e){e.Message=Object.freeze({sendCancellation(e,t){return e.sendNotification(s.type,{id:t})},cleanup(e){}});function t(e){let t=e;return t&&n.func(t.sendCancellation)&&n.func(t.cleanup)}e.is=t})(b||(e.CancellationSenderStrategy=b={}));var ne;(function(e){e.Message=Object.freeze({receiver:y.Message,sender:b.Message});function t(e){let t=e;return t&&y.is(t.receiver)&&b.is(t.sender)}e.is=t})(ne||(e.CancellationStrategy=ne={}));var re;(function(e){function t(e){let t=e;return t&&n.func(t.handleMessage)}e.is=t})(re||(e.MessageStrategy=re={}));var ie;(function(e){function t(e){let t=e;return t&&(ne.is(t.cancellationStrategy)||v.is(t.connectionStrategy)||re.is(t.messageStrategy))}e.is=t})(ie||(e.ConnectionOptions=ie={}));var x;(function(e){e[e.New=1]=`New`,e[e.Listening=2]=`Listening`,e[e.Closed=3]=`Closed`,e[e.Disposed=4]=`Disposed`})(x||={});function ae(f,v,te,y){let b=te===void 0?e.NullLogger:te,ie=0,ae=0,S=0,C,w=new Map,T,oe=new Map,se=new Map,ce,le=new i.LinkedMap,E=new Map,ue=new Set,D=new Map,O=d.Off,de=p.Text,k,A=x.New,fe=new a.Emitter,pe=new a.Emitter,me=new a.Emitter,he=new a.Emitter,ge=new a.Emitter,j=y&&y.cancellationStrategy?y.cancellationStrategy:ne.Message;function _e(e){if(e===null)throw Error(`Can't send requests with id null since the response can't be correlated.`);return`req-`+e.toString()}function ve(e){return e===null?`res-unknown-`+(++S).toString():`res-`+e.toString()}function ye(){return`not-`+(++ae).toString()}function be(e,t){r.Message.isRequest(t)?e.set(_e(t.id),t):r.Message.isResponse(t)?e.set(ve(t.id),t):e.set(ye(),t)}function xe(e){}function M(){return A===x.Listening}function Se(){return A===x.Closed}function N(){return A===x.Disposed}function Ce(){(A===x.New||A===x.Listening)&&(A=x.Closed,pe.fire(void 0))}function we(e){fe.fire([e,void 0,void 0])}function Te(e){fe.fire(e)}f.onClose(Ce),f.onError(we),v.onClose(Ce),v.onError(Te);function Ee(){ce||le.size===0||(ce=(0,t.default)().timer.setImmediate(()=>{ce=void 0,Oe()}))}function De(e){r.Message.isRequest(e)?P(e):r.Message.isNotification(e)?I(e):r.Message.isResponse(e)?F(e):Ae(e)}function Oe(){if(le.size===0)return;let e=le.shift();try{let t=y?.messageStrategy;re.is(t)?t.handleMessage(e,De):De(e)}finally{Ee()}}let ke=e=>{try{if(r.Message.isNotification(e)&&e.method===s.type.method){let t=e.params.id,n=_e(t),i=le.get(n);if(r.Message.isRequest(i)){let r=y?.connectionStrategy,a=r&&r.cancelUndispatched?r.cancelUndispatched(i,xe):void 0;if(a&&(a.error!==void 0||a.result!==void 0)){le.delete(n),D.delete(t),a.id=i.id,R(a,e.method,Date.now()),v.write(a).catch(()=>b.error(`Sending response for canceled message failed.`));return}}let a=D.get(t);if(a!==void 0){a.cancel(),z(e);return}else ue.add(t)}be(le,e)}finally{Ee()}};function P(e){if(N())return;function t(t,n,i){let a={jsonrpc:`2.0`,id:e.id};t instanceof r.ResponseError?a.error=t.toJson():a.result=t===void 0?null:t,R(a,n,i),v.write(a).catch(()=>b.error(`Sending response failed.`))}function i(t,n,r){let i={jsonrpc:`2.0`,id:e.id,error:t.toJson()};R(i,n,r),v.write(i).catch(()=>b.error(`Sending response failed.`))}function a(t,n,r){t===void 0&&(t=null);let i={jsonrpc:`2.0`,id:e.id,result:t};R(i,n,r),v.write(i).catch(()=>b.error(`Sending response failed.`))}Ne(e);let o=w.get(e.method),s,c;o&&(s=o.type,c=o.handler);let l=Date.now();if(c||C){let o=e.id??String(Date.now()),u=ee.is(j.receiver)?j.receiver.createCancellationTokenSource(o):j.receiver.createCancellationTokenSource(e);e.id!==null&&ue.has(e.id)&&u.cancel(),e.id!==null&&D.set(o,u);try{let d;if(c)if(e.params===void 0){if(s!==void 0&&s.numberOfParams!==0){i(new r.ResponseError(r.ErrorCodes.InvalidParams,`Request ${e.method} defines ${s.numberOfParams} params but received none.`),e.method,l);return}d=c(u.token)}else if(Array.isArray(e.params)){if(s!==void 0&&s.parameterStructures===r.ParameterStructures.byName){i(new r.ResponseError(r.ErrorCodes.InvalidParams,`Request ${e.method} defines parameters by name but received parameters by position`),e.method,l);return}d=c(...e.params,u.token)}else{if(s!==void 0&&s.parameterStructures===r.ParameterStructures.byPosition){i(new r.ResponseError(r.ErrorCodes.InvalidParams,`Request ${e.method} defines parameters by position but received parameters by name`),e.method,l);return}d=c(e.params,u.token)}else C&&(d=C(e.method,e.params,u.token));let f=d;d?f.then?f.then(n=>{D.delete(o),t(n,e.method,l)},t=>{D.delete(o),t instanceof r.ResponseError?i(t,e.method,l):t&&n.string(t.message)?i(new r.ResponseError(r.ErrorCodes.InternalError,`Request ${e.method} failed with message: ${t.message}`),e.method,l):i(new r.ResponseError(r.ErrorCodes.InternalError,`Request ${e.method} failed unexpectedly without providing any details.`),e.method,l)}):(D.delete(o),t(d,e.method,l)):(D.delete(o),a(d,e.method,l))}catch(a){D.delete(o),a instanceof r.ResponseError?t(a,e.method,l):a&&n.string(a.message)?i(new r.ResponseError(r.ErrorCodes.InternalError,`Request ${e.method} failed with message: ${a.message}`),e.method,l):i(new r.ResponseError(r.ErrorCodes.InternalError,`Request ${e.method} failed unexpectedly without providing any details.`),e.method,l)}}else i(new r.ResponseError(r.ErrorCodes.MethodNotFound,`Unhandled method ${e.method}`),e.method,l)}function F(e){if(!N())if(e.id===null)e.error?b.error(`Received response message without id: Error is: \n${JSON.stringify(e.error,void 0,4)}`):b.error(`Received response message without id. No further error information provided.`);else{let t=e.id,n=E.get(t);if(Pe(e,n),n!==void 0){E.delete(t);try{if(e.error){let t=e.error;n.reject(new r.ResponseError(t.code,t.message,t.data))}else if(e.result!==void 0)n.resolve(e.result);else throw Error(`Should never happen.`)}catch(e){e.message?b.error(`Response handler '${n.method}' failed with message: ${e.message}`):b.error(`Response handler '${n.method}' failed unexpectedly.`)}}}}function I(e){if(N())return;let t,n;if(e.method===s.type.method){let t=e.params.id;ue.delete(t),z(e);return}else{let r=oe.get(e.method);r&&(n=r.handler,t=r.type)}if(n||T)try{if(z(e),n)if(e.params===void 0)t!==void 0&&t.numberOfParams!==0&&t.parameterStructures!==r.ParameterStructures.byName&&b.error(`Notification ${e.method} defines ${t.numberOfParams} params but received none.`),n();else if(Array.isArray(e.params)){let i=e.params;e.method===l.type.method&&i.length===2&&c.is(i[0])?n({token:i[0],value:i[1]}):(t!==void 0&&(t.parameterStructures===r.ParameterStructures.byName&&b.error(`Notification ${e.method} defines parameters by name but received parameters by position`),t.numberOfParams!==e.params.length&&b.error(`Notification ${e.method} defines ${t.numberOfParams} params but received ${i.length} arguments`)),n(...i))}else t!==void 0&&t.parameterStructures===r.ParameterStructures.byPosition&&b.error(`Notification ${e.method} defines parameters by position but received parameters by name`),n(e.params);else T&&T(e.method,e.params)}catch(t){t.message?b.error(`Notification handler '${e.method}' failed with message: ${t.message}`):b.error(`Notification handler '${e.method}' failed unexpectedly.`)}else me.fire(e)}function Ae(e){if(!e){b.error(`Received empty message.`);return}b.error(`Received message which is neither a response nor a notification message:\n${JSON.stringify(e,null,4)}`);let t=e;if(n.string(t.id)||n.number(t.id)){let e=t.id,n=E.get(e);n&&n.reject(Error(`The received response has neither a result nor an error property.`))}}function L(e){if(e!=null)switch(O){case d.Verbose:return JSON.stringify(e,null,4);case d.Compact:return JSON.stringify(e);default:return}}function je(e){if(!(O===d.Off||!k))if(de===p.Text){let t;(O===d.Verbose||O===d.Compact)&&e.params&&(t=`Params: ${L(e.params)}\n\n`),k.log(`Sending request '${e.method} - (${e.id})'.`,t)}else B(`send-request`,e)}function Me(e){if(!(O===d.Off||!k))if(de===p.Text){let t;(O===d.Verbose||O===d.Compact)&&(t=e.params?`Params: ${L(e.params)}\n\n`:`No parameters provided.
|
|
17
|
+
|
|
18
|
+
`),k.log(`Sending notification '${e.method}'.`,t)}else B(`send-notification`,e)}function R(e,t,n){if(!(O===d.Off||!k))if(de===p.Text){let r;(O===d.Verbose||O===d.Compact)&&(e.error&&e.error.data?r=`Error data: ${L(e.error.data)}\n\n`:e.result?r=`Result: ${L(e.result)}\n\n`:e.error===void 0&&(r=`No result returned.
|
|
19
|
+
|
|
20
|
+
`)),k.log(`Sending response '${t} - (${e.id})'. Processing request took ${Date.now()-n}ms`,r)}else B(`send-response`,e)}function Ne(e){if(!(O===d.Off||!k))if(de===p.Text){let t;(O===d.Verbose||O===d.Compact)&&e.params&&(t=`Params: ${L(e.params)}\n\n`),k.log(`Received request '${e.method} - (${e.id})'.`,t)}else B(`receive-request`,e)}function z(e){if(!(O===d.Off||!k||e.method===h.type.method))if(de===p.Text){let t;(O===d.Verbose||O===d.Compact)&&(t=e.params?`Params: ${L(e.params)}\n\n`:`No parameters provided.
|
|
21
|
+
|
|
22
|
+
`),k.log(`Received notification '${e.method}'.`,t)}else B(`receive-notification`,e)}function Pe(e,t){if(!(O===d.Off||!k))if(de===p.Text){let n;if((O===d.Verbose||O===d.Compact)&&(e.error&&e.error.data?n=`Error data: ${L(e.error.data)}\n\n`:e.result?n=`Result: ${L(e.result)}\n\n`:e.error===void 0&&(n=`No result returned.
|
|
23
|
+
|
|
24
|
+
`)),t){let r=e.error?` Request failed: ${e.error.message} (${e.error.code}).`:``;k.log(`Received response '${t.method} - (${e.id})' in ${Date.now()-t.timerStart}ms.${r}`,n)}else k.log(`Received response ${e.id} without active response promise.`,n)}else B(`receive-response`,e)}function B(e,t){if(!k||O===d.Off)return;let n={isLSPMessage:!0,type:e,message:t,timestamp:Date.now()};k.log(n)}function V(){if(Se())throw new _(g.Closed,`Connection is closed.`);if(N())throw new _(g.Disposed,`Connection is disposed.`)}function Fe(){if(M())throw new _(g.AlreadyListening,`Connection is already listening`)}function Ie(){if(!M())throw Error(`Call listen() first.`)}function Le(e){return e===void 0?null:e}function Re(e){if(e!==null)return e}function ze(e){return e!=null&&!Array.isArray(e)&&typeof e==`object`}function Be(e,t){switch(e){case r.ParameterStructures.auto:return ze(t)?Re(t):[Le(t)];case r.ParameterStructures.byName:if(!ze(t))throw Error(`Received parameters by name but param is not an object literal.`);return Re(t);case r.ParameterStructures.byPosition:return[Le(t)];default:throw Error(`Unknown parameter structure ${e.toString()}`)}}function Ve(e,t){let n,r=e.numberOfParams;switch(r){case 0:n=void 0;break;case 1:n=Be(e.parameterStructures,t[0]);break;default:n=[];for(let e=0;e<t.length&&e<r;e++)n.push(Le(t[e]));if(t.length<r)for(let e=t.length;e<r;e++)n.push(null);break}return n}let He={sendNotification:(e,...t)=>{V();let i,a;if(n.string(e)){i=e;let n=t[0],o=0,s=r.ParameterStructures.auto;r.ParameterStructures.is(n)&&(o=1,s=n);let c=t.length,l=c-o;switch(l){case 0:a=void 0;break;case 1:a=Be(s,t[o]);break;default:if(s===r.ParameterStructures.byName)throw Error(`Received ${l} parameters for 'by Name' notification parameter structure.`);a=t.slice(o,c).map(e=>Le(e));break}}else{let n=t;i=e.method,a=Ve(e,n)}let o={jsonrpc:`2.0`,method:i,params:a};return Me(o),v.write(o).catch(e=>{throw b.error(`Sending notification failed.`),e})},onNotification:(e,t)=>{V();let r;return n.func(e)?T=e:t&&(n.string(e)?(r=e,oe.set(e,{type:void 0,handler:t})):(r=e.method,oe.set(e.method,{type:e,handler:t}))),{dispose:()=>{r===void 0?T=void 0:oe.delete(r)}}},onProgress:(e,t,n)=>{if(se.has(t))throw Error(`Progress handler for token ${t} already registered`);return se.set(t,n),{dispose:()=>{se.delete(t)}}},sendProgress:(e,t,n)=>He.sendNotification(l.type,{token:t,value:n}),onUnhandledProgress:he.event,sendRequest:(e,...t)=>{V(),Ie();let i,a,s;if(n.string(e)){i=e;let n=t[0],c=t[t.length-1],l=0,u=r.ParameterStructures.auto;r.ParameterStructures.is(n)&&(l=1,u=n);let d=t.length;o.CancellationToken.is(c)&&(--d,s=c);let f=d-l;switch(f){case 0:a=void 0;break;case 1:a=Be(u,t[l]);break;default:if(u===r.ParameterStructures.byName)throw Error(`Received ${f} parameters for 'by Name' request parameter structure.`);a=t.slice(l,d).map(e=>Le(e));break}}else{let n=t;i=e.method,a=Ve(e,n);let r=e.numberOfParams;s=o.CancellationToken.is(n[r])?n[r]:void 0}let c=ie++,l;s&&(l=s.onCancellationRequested(()=>{let e=j.sender.sendCancellation(He,c);return e===void 0?(b.log(`Received no promise from cancellation strategy when cancelling id ${c}`),Promise.resolve()):e.catch(()=>{b.log(`Sending cancellation messages for id ${c} failed`)})}));let u={jsonrpc:`2.0`,id:c,method:i,params:a};return je(u),typeof j.sender.enableCancellation==`function`&&j.sender.enableCancellation(u),new Promise(async(e,t)=>{let n={method:i,timerStart:Date.now(),resolve:t=>{e(t),j.sender.cleanup(c),l?.dispose()},reject:e=>{t(e),j.sender.cleanup(c),l?.dispose()}};try{E.set(c,n),await v.write(u)}catch(e){throw E.delete(c),n.reject(new r.ResponseError(r.ErrorCodes.MessageWriteError,e.message?e.message:`Unknown reason`)),b.error(`Sending request failed.`),e}})},onRequest:(e,t)=>{V();let r=null;return u.is(e)?(r=void 0,C=e):n.string(e)?(r=null,t!==void 0&&(r=e,w.set(e,{handler:t,type:void 0}))):t!==void 0&&(r=e.method,w.set(e.method,{type:e,handler:t})),{dispose:()=>{r!==null&&(r===void 0?C=void 0:w.delete(r))}}},hasPendingResponse:()=>E.size>0,trace:async(e,t,r)=>{let i=!1,a=p.Text;r!==void 0&&(n.boolean(r)?i=r:(i=r.sendNotification||!1,a=r.traceFormat||p.Text)),O=e,de=a,k=O===d.Off?void 0:t,i&&!Se()&&!N()&&await He.sendNotification(m.type,{value:d.toString(e)})},onError:fe.event,onClose:pe.event,onUnhandledNotification:me.event,onDispose:ge.event,end:()=>{v.end()},dispose:()=>{if(N())return;A=x.Disposed,ge.fire(void 0);let e=new r.ResponseError(r.ErrorCodes.PendingResponseRejected,`Pending response rejected since connection got disposed`);for(let t of E.values())t.reject(e);E=new Map,D=new Map,ue=new Set,le=new i.LinkedMap,n.func(v.dispose)&&v.dispose(),n.func(f.dispose)&&f.dispose()},listen:()=>{V(),Fe(),A=x.Listening,f.listen(ke)},inspect:()=>{(0,t.default)().console.log(`inspect`)}};return He.onNotification(h.type,e=>{if(O===d.Off||!k)return;let t=O===d.Verbose||O===d.Compact;k.log(e.message,t?e.verbose:void 0)}),He.onNotification(l.type,e=>{let t=se.get(e.token);t?t(e.value):he.fire(e)}),He}e.createMessageConnection=ae})),ir=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0}),e.ProgressType=e.ProgressToken=e.createMessageConnection=e.NullLogger=e.ConnectionOptions=e.ConnectionStrategy=e.AbstractMessageBuffer=e.WriteableStreamMessageWriter=e.AbstractMessageWriter=e.MessageWriter=e.ReadableStreamMessageReader=e.AbstractMessageReader=e.MessageReader=e.SharedArrayReceiverStrategy=e.SharedArraySenderStrategy=e.CancellationToken=e.CancellationTokenSource=e.Emitter=e.Event=e.Disposable=e.LRUCache=e.Touch=e.LinkedMap=e.ParameterStructures=e.NotificationType9=e.NotificationType8=e.NotificationType7=e.NotificationType6=e.NotificationType5=e.NotificationType4=e.NotificationType3=e.NotificationType2=e.NotificationType1=e.NotificationType0=e.NotificationType=e.ErrorCodes=e.ResponseError=e.RequestType9=e.RequestType8=e.RequestType7=e.RequestType6=e.RequestType5=e.RequestType4=e.RequestType3=e.RequestType2=e.RequestType1=e.RequestType0=e.RequestType=e.Message=e.RAL=void 0,e.MessageStrategy=e.CancellationStrategy=e.CancellationSenderStrategy=e.CancellationReceiverStrategy=e.ConnectionError=e.ConnectionErrors=e.LogTraceNotification=e.SetTraceNotification=e.TraceFormat=e.TraceValues=e.Trace=void 0;let t=Kn();Object.defineProperty(e,`Message`,{enumerable:!0,get:function(){return t.Message}}),Object.defineProperty(e,`RequestType`,{enumerable:!0,get:function(){return t.RequestType}}),Object.defineProperty(e,`RequestType0`,{enumerable:!0,get:function(){return t.RequestType0}}),Object.defineProperty(e,`RequestType1`,{enumerable:!0,get:function(){return t.RequestType1}}),Object.defineProperty(e,`RequestType2`,{enumerable:!0,get:function(){return t.RequestType2}}),Object.defineProperty(e,`RequestType3`,{enumerable:!0,get:function(){return t.RequestType3}}),Object.defineProperty(e,`RequestType4`,{enumerable:!0,get:function(){return t.RequestType4}}),Object.defineProperty(e,`RequestType5`,{enumerable:!0,get:function(){return t.RequestType5}}),Object.defineProperty(e,`RequestType6`,{enumerable:!0,get:function(){return t.RequestType6}}),Object.defineProperty(e,`RequestType7`,{enumerable:!0,get:function(){return t.RequestType7}}),Object.defineProperty(e,`RequestType8`,{enumerable:!0,get:function(){return t.RequestType8}}),Object.defineProperty(e,`RequestType9`,{enumerable:!0,get:function(){return t.RequestType9}}),Object.defineProperty(e,`ResponseError`,{enumerable:!0,get:function(){return t.ResponseError}}),Object.defineProperty(e,`ErrorCodes`,{enumerable:!0,get:function(){return t.ErrorCodes}}),Object.defineProperty(e,`NotificationType`,{enumerable:!0,get:function(){return t.NotificationType}}),Object.defineProperty(e,`NotificationType0`,{enumerable:!0,get:function(){return t.NotificationType0}}),Object.defineProperty(e,`NotificationType1`,{enumerable:!0,get:function(){return t.NotificationType1}}),Object.defineProperty(e,`NotificationType2`,{enumerable:!0,get:function(){return t.NotificationType2}}),Object.defineProperty(e,`NotificationType3`,{enumerable:!0,get:function(){return t.NotificationType3}}),Object.defineProperty(e,`NotificationType4`,{enumerable:!0,get:function(){return t.NotificationType4}}),Object.defineProperty(e,`NotificationType5`,{enumerable:!0,get:function(){return t.NotificationType5}}),Object.defineProperty(e,`NotificationType6`,{enumerable:!0,get:function(){return t.NotificationType6}}),Object.defineProperty(e,`NotificationType7`,{enumerable:!0,get:function(){return t.NotificationType7}}),Object.defineProperty(e,`NotificationType8`,{enumerable:!0,get:function(){return t.NotificationType8}}),Object.defineProperty(e,`NotificationType9`,{enumerable:!0,get:function(){return t.NotificationType9}}),Object.defineProperty(e,`ParameterStructures`,{enumerable:!0,get:function(){return t.ParameterStructures}});let n=qn();Object.defineProperty(e,`LinkedMap`,{enumerable:!0,get:function(){return n.LinkedMap}}),Object.defineProperty(e,`LRUCache`,{enumerable:!0,get:function(){return n.LRUCache}}),Object.defineProperty(e,`Touch`,{enumerable:!0,get:function(){return n.Touch}});let r=Jn();Object.defineProperty(e,`Disposable`,{enumerable:!0,get:function(){return r.Disposable}});let i=Xn();Object.defineProperty(e,`Event`,{enumerable:!0,get:function(){return i.Event}}),Object.defineProperty(e,`Emitter`,{enumerable:!0,get:function(){return i.Emitter}});let a=Zn();Object.defineProperty(e,`CancellationTokenSource`,{enumerable:!0,get:function(){return a.CancellationTokenSource}}),Object.defineProperty(e,`CancellationToken`,{enumerable:!0,get:function(){return a.CancellationToken}});let o=Qn();Object.defineProperty(e,`SharedArraySenderStrategy`,{enumerable:!0,get:function(){return o.SharedArraySenderStrategy}}),Object.defineProperty(e,`SharedArrayReceiverStrategy`,{enumerable:!0,get:function(){return o.SharedArrayReceiverStrategy}});let s=er();Object.defineProperty(e,`MessageReader`,{enumerable:!0,get:function(){return s.MessageReader}}),Object.defineProperty(e,`AbstractMessageReader`,{enumerable:!0,get:function(){return s.AbstractMessageReader}}),Object.defineProperty(e,`ReadableStreamMessageReader`,{enumerable:!0,get:function(){return s.ReadableStreamMessageReader}});let c=tr();Object.defineProperty(e,`MessageWriter`,{enumerable:!0,get:function(){return c.MessageWriter}}),Object.defineProperty(e,`AbstractMessageWriter`,{enumerable:!0,get:function(){return c.AbstractMessageWriter}}),Object.defineProperty(e,`WriteableStreamMessageWriter`,{enumerable:!0,get:function(){return c.WriteableStreamMessageWriter}});let l=nr();Object.defineProperty(e,`AbstractMessageBuffer`,{enumerable:!0,get:function(){return l.AbstractMessageBuffer}});let u=rr();Object.defineProperty(e,`ConnectionStrategy`,{enumerable:!0,get:function(){return u.ConnectionStrategy}}),Object.defineProperty(e,`ConnectionOptions`,{enumerable:!0,get:function(){return u.ConnectionOptions}}),Object.defineProperty(e,`NullLogger`,{enumerable:!0,get:function(){return u.NullLogger}}),Object.defineProperty(e,`createMessageConnection`,{enumerable:!0,get:function(){return u.createMessageConnection}}),Object.defineProperty(e,`ProgressToken`,{enumerable:!0,get:function(){return u.ProgressToken}}),Object.defineProperty(e,`ProgressType`,{enumerable:!0,get:function(){return u.ProgressType}}),Object.defineProperty(e,`Trace`,{enumerable:!0,get:function(){return u.Trace}}),Object.defineProperty(e,`TraceValues`,{enumerable:!0,get:function(){return u.TraceValues}}),Object.defineProperty(e,`TraceFormat`,{enumerable:!0,get:function(){return u.TraceFormat}}),Object.defineProperty(e,`SetTraceNotification`,{enumerable:!0,get:function(){return u.SetTraceNotification}}),Object.defineProperty(e,`LogTraceNotification`,{enumerable:!0,get:function(){return u.LogTraceNotification}}),Object.defineProperty(e,`ConnectionErrors`,{enumerable:!0,get:function(){return u.ConnectionErrors}}),Object.defineProperty(e,`ConnectionError`,{enumerable:!0,get:function(){return u.ConnectionError}}),Object.defineProperty(e,`CancellationReceiverStrategy`,{enumerable:!0,get:function(){return u.CancellationReceiverStrategy}}),Object.defineProperty(e,`CancellationSenderStrategy`,{enumerable:!0,get:function(){return u.CancellationSenderStrategy}}),Object.defineProperty(e,`CancellationStrategy`,{enumerable:!0,get:function(){return u.CancellationStrategy}}),Object.defineProperty(e,`MessageStrategy`,{enumerable:!0,get:function(){return u.MessageStrategy}}),e.RAL=Yn().default})),ar=S((e=>{Object.defineProperty(e,`__esModule`,{value:!0});let t=C(`util`),n=ir();var r=class e extends n.AbstractMessageBuffer{constructor(e=`utf-8`){super(e)}emptyBuffer(){return e.emptyBuffer}fromString(e,t){return Buffer.from(e,t)}toString(e,n){return e instanceof Buffer?e.toString(n):new t.TextDecoder(n).decode(e)}asNative(e,t){return t===void 0?e instanceof Buffer?e:Buffer.from(e):e instanceof Buffer?e.slice(0,t):Buffer.from(e,0,t)}allocNative(e){return Buffer.allocUnsafe(e)}};r.emptyBuffer=Buffer.allocUnsafe(0);var i=class{constructor(e){this.stream=e}onClose(e){return this.stream.on(`close`,e),n.Disposable.create(()=>this.stream.off(`close`,e))}onError(e){return this.stream.on(`error`,e),n.Disposable.create(()=>this.stream.off(`error`,e))}onEnd(e){return this.stream.on(`end`,e),n.Disposable.create(()=>this.stream.off(`end`,e))}onData(e){return this.stream.on(`data`,e),n.Disposable.create(()=>this.stream.off(`data`,e))}},a=class{constructor(e){this.stream=e}onClose(e){return this.stream.on(`close`,e),n.Disposable.create(()=>this.stream.off(`close`,e))}onError(e){return this.stream.on(`error`,e),n.Disposable.create(()=>this.stream.off(`error`,e))}onEnd(e){return this.stream.on(`end`,e),n.Disposable.create(()=>this.stream.off(`end`,e))}write(e,t){return new Promise((n,r)=>{let i=e=>{e==null?n():r(e)};typeof e==`string`?this.stream.write(e,t,i):this.stream.write(e,i)})}end(){this.stream.end()}};let o=Object.freeze({messageBuffer:Object.freeze({create:e=>new r(e)}),applicationJson:Object.freeze({encoder:Object.freeze({name:`application/json`,encode:(e,t)=>{try{return Promise.resolve(Buffer.from(JSON.stringify(e,void 0,0),t.charset))}catch(e){return Promise.reject(e)}}}),decoder:Object.freeze({name:`application/json`,decode:(e,n)=>{try{return e instanceof Buffer?Promise.resolve(JSON.parse(e.toString(n.charset))):Promise.resolve(JSON.parse(new t.TextDecoder(n.charset).decode(e)))}catch(e){return Promise.reject(e)}}})}),stream:Object.freeze({asReadableStream:e=>new i(e),asWritableStream:e=>new a(e)}),console,timer:Object.freeze({setTimeout(e,t,...n){let r=setTimeout(e,t,...n);return{dispose:()=>clearTimeout(r)}},setImmediate(e,...t){let n=setImmediate(e,...t);return{dispose:()=>clearImmediate(n)}},setInterval(e,t,...n){let r=setInterval(e,t,...n);return{dispose:()=>clearInterval(r)}}})});function s(){return o}(function(e){function t(){n.RAL.install(o)}e.install=t})(s||={}),e.default=s})),or=S((e=>{var t=e&&e.__createBinding||(Object.create?(function(e,t,n,r){r===void 0&&(r=n);var i=Object.getOwnPropertyDescriptor(t,n);(!i||(`get`in i?!t.__esModule:i.writable||i.configurable))&&(i={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,i)}):(function(e,t,n,r){r===void 0&&(r=n),e[r]=t[n]})),n=e&&e.__exportStar||function(e,n){for(var r in e)r!==`default`&&!Object.prototype.hasOwnProperty.call(n,r)&&t(n,e,r)};Object.defineProperty(e,`__esModule`,{value:!0}),e.createMessageConnection=e.createServerSocketTransport=e.createClientSocketTransport=e.createServerPipeTransport=e.createClientPipeTransport=e.generateRandomPipeName=e.StreamMessageWriter=e.StreamMessageReader=e.SocketMessageWriter=e.SocketMessageReader=e.PortMessageWriter=e.PortMessageReader=e.IPCMessageWriter=e.IPCMessageReader=void 0;let r=ar();r.default.install();let i=C(`path`),a=C(`os`),o=C(`crypto`),s=C(`net`),c=ir();n(ir(),e),e.IPCMessageReader=class extends c.AbstractMessageReader{constructor(e){super(),this.process=e;let t=this.process;t.on(`error`,e=>this.fireError(e)),t.on(`close`,()=>this.fireClose())}listen(e){return this.process.on(`message`,e),c.Disposable.create(()=>this.process.off(`message`,e))}},e.IPCMessageWriter=class extends c.AbstractMessageWriter{constructor(e){super(),this.process=e,this.errorCount=0;let t=this.process;t.on(`error`,e=>this.fireError(e)),t.on(`close`,()=>this.fireClose)}write(e){try{return typeof this.process.send==`function`&&this.process.send(e,void 0,void 0,t=>{t?(this.errorCount++,this.handleError(t,e)):this.errorCount=0}),Promise.resolve()}catch(t){return this.handleError(t,e),Promise.reject(t)}}handleError(e,t){this.errorCount++,this.fireError(e,t,this.errorCount)}end(){}},e.PortMessageReader=class extends c.AbstractMessageReader{constructor(e){super(),this.onData=new c.Emitter,e.on(`close`,()=>this.fireClose),e.on(`error`,e=>this.fireError(e)),e.on(`message`,e=>{this.onData.fire(e)})}listen(e){return this.onData.event(e)}},e.PortMessageWriter=class extends c.AbstractMessageWriter{constructor(e){super(),this.port=e,this.errorCount=0,e.on(`close`,()=>this.fireClose()),e.on(`error`,e=>this.fireError(e))}write(e){try{return this.port.postMessage(e),Promise.resolve()}catch(t){return this.handleError(t,e),Promise.reject(t)}}handleError(e,t){this.errorCount++,this.fireError(e,t,this.errorCount)}end(){}};var l=class extends c.ReadableStreamMessageReader{constructor(e,t=`utf-8`){super((0,r.default)().stream.asReadableStream(e),t)}};e.SocketMessageReader=l;var u=class extends c.WriteableStreamMessageWriter{constructor(e,t){super((0,r.default)().stream.asWritableStream(e),t),this.socket=e}dispose(){super.dispose(),this.socket.destroy()}};e.SocketMessageWriter=u;var d=class extends c.ReadableStreamMessageReader{constructor(e,t){super((0,r.default)().stream.asReadableStream(e),t)}};e.StreamMessageReader=d;var f=class extends c.WriteableStreamMessageWriter{constructor(e,t){super((0,r.default)().stream.asWritableStream(e),t)}};e.StreamMessageWriter=f;let p=process.env.XDG_RUNTIME_DIR,m=new Map([[`linux`,107],[`darwin`,103]]);function h(){let e=(0,o.randomBytes)(21).toString(`hex`);if(process.platform===`win32`)return`\\\\.\\pipe\\vscode-jsonrpc-${e}-sock`;let t;t=p?i.join(p,`vscode-ipc-${e}.sock`):i.join(a.tmpdir(),`vscode-${e}.sock`);let n=m.get(process.platform);return n!==void 0&&t.length>n&&(0,r.default)().console.warn(`WARNING: IPC handle "${t}" is longer than ${n} characters.`),t}e.generateRandomPipeName=h;function g(e,t=`utf-8`){let n,r=new Promise((e,t)=>{n=e});return new Promise((i,a)=>{let o=(0,s.createServer)(e=>{o.close(),n([new l(e,t),new u(e,t)])});o.on(`error`,a),o.listen(e,()=>{o.removeListener(`error`,a),i({onConnected:()=>r})})})}e.createClientPipeTransport=g;function _(e,t=`utf-8`){let n=(0,s.createConnection)(e);return[new l(n,t),new u(n,t)]}e.createServerPipeTransport=_;function v(e,t=`utf-8`){let n,r=new Promise((e,t)=>{n=e});return new Promise((i,a)=>{let o=(0,s.createServer)(e=>{o.close(),n([new l(e,t),new u(e,t)])});o.on(`error`,a),o.listen(e,`127.0.0.1`,()=>{o.removeListener(`error`,a),i({onConnected:()=>r})})})}e.createClientSocketTransport=v;function ee(e,t=`utf-8`){let n=(0,s.createConnection)(e,`127.0.0.1`);return[new l(n,t),new u(n,t)]}e.createServerSocketTransport=ee;function te(e){let t=e;return t.read!==void 0&&t.addListener!==void 0}function y(e){let t=e;return t.write!==void 0&&t.addListener!==void 0}function b(e,t,n,r){n||=c.NullLogger;let i=te(e)?new d(e):e,a=y(t)?new f(t):t;return c.ConnectionStrategy.is(r)&&(r={connectionStrategy:r}),(0,c.createMessageConnection)(i,a,n,r)}e.createMessageConnection=b})),X=S(((e,t)=>{t.exports=or()}))();function sr(e){return{ping:async t=>e.sendRequest(`ping`,t),models:{list:async()=>e.sendRequest(`models.list`,{})},tools:{list:async t=>e.sendRequest(`tools.list`,t)},account:{getQuota:async()=>e.sendRequest(`account.getQuota`,{})}}}function cr(e,t){return{model:{getCurrent:async()=>e.sendRequest(`session.model.getCurrent`,{sessionId:t}),switchTo:async n=>e.sendRequest(`session.model.switchTo`,{sessionId:t,...n})},mode:{get:async()=>e.sendRequest(`session.mode.get`,{sessionId:t}),set:async n=>e.sendRequest(`session.mode.set`,{sessionId:t,...n})},plan:{read:async()=>e.sendRequest(`session.plan.read`,{sessionId:t}),update:async n=>e.sendRequest(`session.plan.update`,{sessionId:t,...n}),delete:async()=>e.sendRequest(`session.plan.delete`,{sessionId:t})},workspace:{listFiles:async()=>e.sendRequest(`session.workspace.listFiles`,{sessionId:t}),readFile:async n=>e.sendRequest(`session.workspace.readFile`,{sessionId:t,...n}),createFile:async n=>e.sendRequest(`session.workspace.createFile`,{sessionId:t,...n})},fleet:{start:async n=>e.sendRequest(`session.fleet.start`,{sessionId:t,...n})},agent:{list:async()=>e.sendRequest(`session.agent.list`,{sessionId:t}),getCurrent:async()=>e.sendRequest(`session.agent.getCurrent`,{sessionId:t}),select:async n=>e.sendRequest(`session.agent.select`,{sessionId:t,...n}),deselect:async()=>e.sendRequest(`session.agent.deselect`,{sessionId:t})},compaction:{compact:async()=>e.sendRequest(`session.compaction.compact`,{sessionId:t})},tools:{handlePendingToolCall:async n=>e.sendRequest(`session.tools.handlePendingToolCall`,{sessionId:t,...n})},permissions:{handlePendingPermissionRequest:async n=>e.sendRequest(`session.permissions.handlePendingPermissionRequest`,{sessionId:t,...n})}}}function lr(){return 3}var ur=class{constructor(e,t,n){this.sessionId=e,this.connection=t,this._workspacePath=n}eventHandlers=new Set;typedEventHandlers=new Map;toolHandlers=new Map;permissionHandler;userInputHandler;hooks;_rpc=null;get rpc(){return this._rpc||=cr(this.connection,this.sessionId),this._rpc}get workspacePath(){return this._workspacePath}async send(e){return(await this.connection.sendRequest(`session.send`,{sessionId:this.sessionId,prompt:e.prompt,attachments:e.attachments,mode:e.mode})).messageId}async sendAndWait(e,t){let n=t??6e4,r,i,a=new Promise((e,t)=>{r=e,i=t}),o,s=this.on(e=>{if(e.type===`assistant.message`)o=e;else if(e.type===`session.idle`)r();else if(e.type===`session.error`){let t=Error(e.data.message);t.stack=e.data.stack,i(t)}}),c;try{await this.send(e);let t=new Promise((e,t)=>{c=setTimeout(()=>t(Error(`Timeout after ${n}ms waiting for session.idle`)),n)});return await Promise.race([a,t]),o}finally{c!==void 0&&clearTimeout(c),s()}}on(e,t){if(typeof e==`string`&&t){let n=e;this.typedEventHandlers.has(n)||this.typedEventHandlers.set(n,new Set);let r=t;return this.typedEventHandlers.get(n).add(r),()=>{let e=this.typedEventHandlers.get(n);e&&e.delete(r)}}let n=e;return this.eventHandlers.add(n),()=>{this.eventHandlers.delete(n)}}_dispatchEvent(e){this._handleBroadcastEvent(e);let t=this.typedEventHandlers.get(e.type);if(t)for(let n of t)try{n(e)}catch{}for(let t of this.eventHandlers)try{t(e)}catch{}}_handleBroadcastEvent(e){if(e.type===`external_tool.requested`){let{requestId:t,toolName:n}=e.data,r=e.data.arguments,i=e.data.toolCallId,a=this.toolHandlers.get(n);a&&this._executeToolAndRespond(t,n,i,r,a)}else if(e.type===`permission.requested`){let{requestId:t,permissionRequest:n}=e.data;this.permissionHandler&&this._executePermissionAndRespond(t,n)}}async _executeToolAndRespond(e,t,n,r,i){try{let a=await i(r,{sessionId:this.sessionId,toolCallId:n,toolName:t,arguments:r}),o;o=a==null?``:typeof a==`string`?a:JSON.stringify(a),await this.rpc.tools.handlePendingToolCall({requestId:e,result:o})}catch(t){let n=t instanceof Error?t.message:String(t);try{await this.rpc.tools.handlePendingToolCall({requestId:e,error:n})}catch(e){if(!(e instanceof X.ConnectionError||e instanceof X.ResponseError))throw e}}}async _executePermissionAndRespond(e,t){try{let n=await this.permissionHandler(t,{sessionId:this.sessionId});await this.rpc.permissions.handlePendingPermissionRequest({requestId:e,result:n})}catch{try{await this.rpc.permissions.handlePendingPermissionRequest({requestId:e,result:{kind:`denied-no-approval-rule-and-could-not-request-from-user`}})}catch(e){if(!(e instanceof X.ConnectionError||e instanceof X.ResponseError))throw e}}}registerTools(e){if(this.toolHandlers.clear(),e)for(let t of e)this.toolHandlers.set(t.name,t.handler)}getToolHandler(e){return this.toolHandlers.get(e)}registerPermissionHandler(e){this.permissionHandler=e}registerUserInputHandler(e){this.userInputHandler=e}registerHooks(e){this.hooks=e}async _handlePermissionRequestV2(e){if(!this.permissionHandler)return{kind:`denied-no-approval-rule-and-could-not-request-from-user`};try{return await this.permissionHandler(e,{sessionId:this.sessionId})}catch{return{kind:`denied-no-approval-rule-and-could-not-request-from-user`}}}async _handleUserInputRequest(e){if(!this.userInputHandler)throw Error(`User input requested but no handler registered`);try{return await this.userInputHandler(e,{sessionId:this.sessionId})}catch(e){throw e}}async _handleHooksInvoke(e,t){if(!this.hooks)return;let n={preToolUse:this.hooks.onPreToolUse,postToolUse:this.hooks.onPostToolUse,userPromptSubmitted:this.hooks.onUserPromptSubmitted,sessionStart:this.hooks.onSessionStart,sessionEnd:this.hooks.onSessionEnd,errorOccurred:this.hooks.onErrorOccurred}[e];if(n)try{return await n(t,{sessionId:this.sessionId})}catch{return}}async getMessages(){return(await this.connection.sendRequest(`session.getMessages`,{sessionId:this.sessionId})).events}async disconnect(){await this.connection.sendRequest(`session.destroy`,{sessionId:this.sessionId}),this.eventHandlers.clear(),this.typedEventHandlers.clear(),this.toolHandlers.clear(),this.permissionHandler=void 0}async destroy(){return this.disconnect()}async[Symbol.asyncDispose](){return this.disconnect()}async abort(){await this.connection.sendRequest(`session.abort`,{sessionId:this.sessionId})}async setModel(e){await this.rpc.model.switchTo({modelId:e})}};function dr(e){return typeof e==`object`&&!!e&&`toJSONSchema`in e&&typeof e.toJSONSchema==`function`}function fr(e){if(e)return dr(e)?e.toJSONSchema():e}function pr(){return process.versions.bun?`node`:process.execPath}function mr(){return v(_(_(ne(import.meta.resolve(`@github/copilot/sdk`)))),`index.js`)}var hr=class{cliProcess=null;connection=null;socket=null;actualPort=null;actualHost=`localhost`;state=`disconnected`;sessions=new Map;stderrBuffer=``;options;isExternalServer=!1;forceStopping=!1;modelsCache=null;modelsCacheLock=Promise.resolve();sessionLifecycleHandlers=new Set;typedLifecycleHandlers=new Map;_rpc=null;processExitPromise=null;negotiatedProtocolVersion=null;get rpc(){if(!this.connection)throw Error(`Client is not connected. Call start() first.`);return this._rpc||=sr(this.connection),this._rpc}constructor(e={}){if(e.cliUrl&&(e.useStdio===!0||e.cliPath))throw Error(`cliUrl is mutually exclusive with useStdio and cliPath`);if(e.isChildProcess&&(e.cliUrl||e.useStdio===!1))throw Error(`isChildProcess must be used in conjunction with useStdio and not with cliUrl`);if(e.cliUrl&&(e.githubToken||e.useLoggedInUser!==void 0))throw Error(`githubToken and useLoggedInUser cannot be used with cliUrl (external server manages its own auth)`);if(e.cliUrl){let{host:t,port:n}=this.parseCliUrl(e.cliUrl);this.actualHost=t,this.actualPort=n,this.isExternalServer=!0}e.isChildProcess&&(this.isExternalServer=!0),this.options={cliPath:e.cliPath||mr(),cliArgs:e.cliArgs??[],cwd:e.cwd??process.cwd(),port:e.port||0,useStdio:e.cliUrl?!1:e.useStdio??!0,isChildProcess:e.isChildProcess??!1,cliUrl:e.cliUrl,logLevel:e.logLevel||`debug`,autoStart:e.autoStart??!0,autoRestart:e.autoRestart??!0,env:e.env??process.env,githubToken:e.githubToken,useLoggedInUser:e.useLoggedInUser??!e.githubToken}}parseCliUrl(e){let t=e.replace(/^https?:\/\//,``);if(/^\d+$/.test(t))return{host:`localhost`,port:parseInt(t,10)};let n=t.split(`:`);if(n.length!==2)throw Error(`Invalid cliUrl format: ${e}. Expected "host:port", "http://host:port", or "port"`);let r=n[0]||`localhost`,i=parseInt(n[1],10);if(isNaN(i)||i<=0||i>65535)throw Error(`Invalid port in cliUrl: ${e}`);return{host:r,port:i}}async start(){if(this.state!==`connected`){this.state=`connecting`;try{this.isExternalServer||await this.startCLIServer(),await this.connectToServer(),await this.verifyProtocolVersion(),this.state=`connected`}catch(e){throw this.state=`error`,e}}}async stop(){let e=[];for(let t of this.sessions.values()){let n=t.sessionId,r=null;for(let e=1;e<=3;e++)try{await t.disconnect(),r=null;break}catch(t){if(r=t instanceof Error?t:Error(String(t)),e<3){let t=100*2**(e-1);await new Promise(e=>setTimeout(e,t))}}r&&e.push(Error(`Failed to disconnect session ${n} after 3 attempts: ${r.message}`))}if(this.sessions.clear(),this.connection){try{this.connection.dispose()}catch(t){e.push(Error(`Failed to dispose connection: ${t instanceof Error?t.message:String(t)}`))}this.connection=null,this._rpc=null}if(this.modelsCache=null,this.socket){try{this.socket.end()}catch(t){e.push(Error(`Failed to close socket: ${t instanceof Error?t.message:String(t)}`))}this.socket=null}if(this.cliProcess&&!this.isExternalServer){try{this.cliProcess.kill()}catch(t){e.push(Error(`Failed to kill CLI process: ${t instanceof Error?t.message:String(t)}`))}this.cliProcess=null}return this.state=`disconnected`,this.actualPort=null,this.stderrBuffer=``,this.processExitPromise=null,e}async forceStop(){if(this.forceStopping=!0,this.sessions.clear(),this.connection){try{this.connection.dispose()}catch{}this.connection=null,this._rpc=null}if(this.modelsCache=null,this.socket){try{this.socket.destroy()}catch{}this.socket=null}if(this.cliProcess&&!this.isExternalServer){try{this.cliProcess.kill(`SIGKILL`)}catch{}this.cliProcess=null}this.state=`disconnected`,this.actualPort=null,this.stderrBuffer=``,this.processExitPromise=null}async createSession(e){if(!e?.onPermissionRequest)throw Error(`An onPermissionRequest handler is required when creating a session. For example, to allow all permissions, use { onPermissionRequest: approveAll }.`);if(!this.connection)if(this.options.autoStart)await this.start();else throw Error(`Client not connected. Call start() first.`);let{sessionId:t,workspacePath:n}=await this.connection.sendRequest(`session.create`,{model:e.model,sessionId:e.sessionId,clientName:e.clientName,reasoningEffort:e.reasoningEffort,tools:e.tools?.map(e=>({name:e.name,description:e.description,parameters:fr(e.parameters),overridesBuiltInTool:e.overridesBuiltInTool})),systemMessage:e.systemMessage,availableTools:e.availableTools,excludedTools:e.excludedTools,provider:e.provider,requestPermission:!0,requestUserInput:!!e.onUserInputRequest,hooks:!!(e.hooks&&Object.values(e.hooks).some(Boolean)),workingDirectory:e.workingDirectory,streaming:e.streaming,mcpServers:e.mcpServers,envValueMode:`direct`,customAgents:e.customAgents,configDir:e.configDir,skillDirectories:e.skillDirectories,disabledSkills:e.disabledSkills,infiniteSessions:e.infiniteSessions}),r=new ur(t,this.connection,n);return r.registerTools(e.tools),r.registerPermissionHandler(e.onPermissionRequest),e.onUserInputRequest&&r.registerUserInputHandler(e.onUserInputRequest),e.hooks&&r.registerHooks(e.hooks),this.sessions.set(t,r),r}async resumeSession(e,t){if(!t?.onPermissionRequest)throw Error(`An onPermissionRequest handler is required when resuming a session. For example, to allow all permissions, use { onPermissionRequest: approveAll }.`);if(!this.connection)if(this.options.autoStart)await this.start();else throw Error(`Client not connected. Call start() first.`);let{sessionId:n,workspacePath:r}=await this.connection.sendRequest(`session.resume`,{sessionId:e,clientName:t.clientName,model:t.model,reasoningEffort:t.reasoningEffort,systemMessage:t.systemMessage,availableTools:t.availableTools,excludedTools:t.excludedTools,tools:t.tools?.map(e=>({name:e.name,description:e.description,parameters:fr(e.parameters),overridesBuiltInTool:e.overridesBuiltInTool})),provider:t.provider,requestPermission:!0,requestUserInput:!!t.onUserInputRequest,hooks:!!(t.hooks&&Object.values(t.hooks).some(Boolean)),workingDirectory:t.workingDirectory,configDir:t.configDir,streaming:t.streaming,mcpServers:t.mcpServers,envValueMode:`direct`,customAgents:t.customAgents,skillDirectories:t.skillDirectories,disabledSkills:t.disabledSkills,infiniteSessions:t.infiniteSessions,disableResume:t.disableResume}),i=new ur(n,this.connection,r);return i.registerTools(t.tools),i.registerPermissionHandler(t.onPermissionRequest),t.onUserInputRequest&&i.registerUserInputHandler(t.onUserInputRequest),t.hooks&&i.registerHooks(t.hooks),this.sessions.set(n,i),i}getState(){return this.state}async ping(e){if(!this.connection)throw Error(`Client not connected`);return await this.connection.sendRequest(`ping`,{message:e})}async getStatus(){if(!this.connection)throw Error(`Client not connected`);return await this.connection.sendRequest(`status.get`,{})}async getAuthStatus(){if(!this.connection)throw Error(`Client not connected`);return await this.connection.sendRequest(`auth.getStatus`,{})}async listModels(){if(!this.connection)throw Error(`Client not connected`);await this.modelsCacheLock;let e;this.modelsCacheLock=new Promise(t=>{e=t});try{if(this.modelsCache!==null)return[...this.modelsCache];let e=(await this.connection.sendRequest(`models.list`,{})).models;return this.modelsCache=e,[...e]}finally{e()}}async verifyProtocolVersion(){let e=lr(),t;t=this.processExitPromise?await Promise.race([this.ping(),this.processExitPromise]):await this.ping();let n=t.protocolVersion;if(n===void 0)throw Error(`SDK protocol version mismatch: SDK supports versions 2-${e}, but server does not report a protocol version. Please update your server to ensure compatibility.`);if(n<2||n>e)throw Error(`SDK protocol version mismatch: SDK supports versions 2-${e}, but server reports version ${n}. Please update your SDK or server to ensure compatibility.`);this.negotiatedProtocolVersion=n}async getLastSessionId(){if(!this.connection)throw Error(`Client not connected`);return(await this.connection.sendRequest(`session.getLastId`,{})).sessionId}async deleteSession(e){if(!this.connection)throw Error(`Client not connected`);let{success:t,error:n}=await this.connection.sendRequest(`session.delete`,{sessionId:e});if(!t)throw Error(`Failed to delete session ${e}: ${n||`Unknown error`}`);this.sessions.delete(e)}async listSessions(e){if(!this.connection)throw Error(`Client not connected`);let{sessions:t}=await this.connection.sendRequest(`session.list`,{filter:e});return t.map(e=>({sessionId:e.sessionId,startTime:new Date(e.startTime),modifiedTime:new Date(e.modifiedTime),summary:e.summary,isRemote:e.isRemote,context:e.context}))}async getForegroundSessionId(){if(!this.connection)throw Error(`Client not connected`);return(await this.connection.sendRequest(`session.getForeground`,{})).sessionId}async setForegroundSessionId(e){if(!this.connection)throw Error(`Client not connected`);let t=await this.connection.sendRequest(`session.setForeground`,{sessionId:e});if(!t.success)throw Error(t.error||`Failed to set foreground session`)}on(e,t){if(typeof e==`string`&&t){let n=e;this.typedLifecycleHandlers.has(n)||this.typedLifecycleHandlers.set(n,new Set);let r=t;return this.typedLifecycleHandlers.get(n).add(r),()=>{let e=this.typedLifecycleHandlers.get(n);e&&e.delete(r)}}let n=e;return this.sessionLifecycleHandlers.add(n),()=>{this.sessionLifecycleHandlers.delete(n)}}async startCLIServer(){return new Promise((e,t)=>{this.stderrBuffer=``;let n=[...this.options.cliArgs,`--headless`,`--no-auto-update`,`--log-level`,this.options.logLevel];this.options.useStdio?n.push(`--stdio`):this.options.port>0&&n.push(`--port`,this.options.port.toString()),this.options.githubToken&&n.push(`--auth-token-env`,`COPILOT_SDK_AUTH_TOKEN`),this.options.useLoggedInUser||n.push(`--no-auto-login`);let i={...this.options.env};if(delete i.NODE_DEBUG,this.options.githubToken&&(i.COPILOT_SDK_AUTH_TOKEN=this.options.githubToken),!y(this.options.cliPath))throw Error(`Copilot CLI not found at ${this.options.cliPath}. Ensure @github/copilot is installed.`);let a=this.options.useStdio?[`pipe`,`pipe`,`pipe`]:[`ignore`,`pipe`,`pipe`];this.options.cliPath.endsWith(`.js`)?this.cliProcess=r(pr(),[this.options.cliPath,...n],{stdio:a,cwd:this.options.cwd,env:i,windowsHide:!0}):this.cliProcess=r(this.options.cliPath,n,{stdio:a,cwd:this.options.cwd,env:i,windowsHide:!0});let o=``,s=!1;this.options.useStdio?(s=!0,e()):this.cliProcess.stdout?.on(`data`,t=>{o+=t.toString();let n=o.match(/listening on port (\d+)/i);n&&!s&&(this.actualPort=parseInt(n[1],10),s=!0,e())}),this.cliProcess.stderr?.on(`data`,e=>{this.stderrBuffer+=e.toString();let t=e.toString().split(`
|
|
25
|
+
`);for(let e of t)e.trim()&&process.stderr.write(`[CLI subprocess] ${e}
|
|
26
|
+
`)}),this.cliProcess.on(`error`,e=>{if(!s){s=!0;let n=this.stderrBuffer.trim();t(n?Error(`Failed to start CLI server: ${e.message}
|
|
27
|
+
stderr: ${n}`):Error(`Failed to start CLI server: ${e.message}`))}}),this.processExitPromise=new Promise((e,t)=>{this.cliProcess.on(`exit`,e=>{setTimeout(()=>{let n=this.stderrBuffer.trim();t(n?Error(`CLI server exited with code ${e}
|
|
28
|
+
stderr: ${n}`):Error(`CLI server exited unexpectedly with code ${e}`))},50)})}),this.processExitPromise.catch(()=>{}),this.cliProcess.on(`exit`,e=>{if(s)this.options.autoRestart&&this.state===`connected`&&this.reconnect();else{s=!0;let n=this.stderrBuffer.trim();t(n?Error(`CLI server exited with code ${e}
|
|
29
|
+
stderr: ${n}`):Error(`CLI server exited with code ${e}`))}}),setTimeout(()=>{s||(s=!0,t(Error(`Timeout waiting for CLI server to start`)))},1e4)})}async connectToServer(){return this.options.isChildProcess?this.connectToParentProcessViaStdio():this.options.useStdio?this.connectToChildProcessViaStdio():this.connectViaTcp()}async connectToChildProcessViaStdio(){if(!this.cliProcess)throw Error(`CLI process not started`);this.cliProcess.stdin?.on(`error`,e=>{if(!this.forceStopping)throw e}),this.connection=(0,X.createMessageConnection)(new X.StreamMessageReader(this.cliProcess.stdout),new X.StreamMessageWriter(this.cliProcess.stdin)),this.attachConnectionHandlers(),this.connection.listen()}async connectToParentProcessViaStdio(){if(this.cliProcess)throw Error(`CLI child process was unexpectedly started in parent process mode`);this.connection=(0,X.createMessageConnection)(new X.StreamMessageReader(process.stdin),new X.StreamMessageWriter(process.stdout)),this.attachConnectionHandlers(),this.connection.listen()}async connectViaTcp(){if(!this.actualPort)throw Error(`Server port not available`);return new Promise((e,t)=>{this.socket=new b,this.socket.connect(this.actualPort,this.actualHost,()=>{this.connection=(0,X.createMessageConnection)(new X.StreamMessageReader(this.socket),new X.StreamMessageWriter(this.socket)),this.attachConnectionHandlers(),this.connection.listen(),e()}),this.socket.on(`error`,e=>{t(Error(`Failed to connect to CLI server: ${e.message}`))})})}attachConnectionHandlers(){this.connection&&(this.connection.onNotification(`session.event`,e=>{this.handleSessionEventNotification(e)}),this.connection.onNotification(`session.lifecycle`,e=>{this.handleSessionLifecycleNotification(e)}),this.connection.onRequest(`tool.call`,async e=>await this.handleToolCallRequestV2(e)),this.connection.onRequest(`permission.request`,async e=>await this.handlePermissionRequestV2(e)),this.connection.onRequest(`userInput.request`,async e=>await this.handleUserInputRequest(e)),this.connection.onRequest(`hooks.invoke`,async e=>await this.handleHooksInvoke(e)),this.connection.onClose(()=>{this.state===`connected`&&this.options.autoRestart&&this.reconnect()}),this.connection.onError(e=>{}))}handleSessionEventNotification(e){if(typeof e!=`object`||!e||!(`sessionId`in e)||typeof e.sessionId!=`string`||!(`event`in e))return;let t=this.sessions.get(e.sessionId);t&&t._dispatchEvent(e.event)}handleSessionLifecycleNotification(e){if(typeof e!=`object`||!e||!(`type`in e)||typeof e.type!=`string`||!(`sessionId`in e)||typeof e.sessionId!=`string`)return;let t=e,n=this.typedLifecycleHandlers.get(t.type);if(n)for(let e of n)try{e(t)}catch{}for(let e of this.sessionLifecycleHandlers)try{e(t)}catch{}}async handleUserInputRequest(e){if(!e||typeof e.sessionId!=`string`||typeof e.question!=`string`)throw Error(`Invalid user input request payload`);let t=this.sessions.get(e.sessionId);if(!t)throw Error(`Session not found: ${e.sessionId}`);return await t._handleUserInputRequest({question:e.question,choices:e.choices,allowFreeform:e.allowFreeform})}async handleHooksInvoke(e){if(!e||typeof e.sessionId!=`string`||typeof e.hookType!=`string`)throw Error(`Invalid hooks invoke payload`);let t=this.sessions.get(e.sessionId);if(!t)throw Error(`Session not found: ${e.sessionId}`);return{output:await t._handleHooksInvoke(e.hookType,e.input)}}async handleToolCallRequestV2(e){if(!e||typeof e.sessionId!=`string`||typeof e.toolCallId!=`string`||typeof e.toolName!=`string`)throw Error(`Invalid tool call payload`);let t=this.sessions.get(e.sessionId);if(!t)throw Error(`Unknown session ${e.sessionId}`);let n=t.getToolHandler(e.toolName);if(!n)return{result:{textResultForLlm:`Tool '${e.toolName}' is not supported by this client instance.`,resultType:`failure`,error:`tool '${e.toolName}' not supported`,toolTelemetry:{}}};try{let t={sessionId:e.sessionId,toolCallId:e.toolCallId,toolName:e.toolName,arguments:e.arguments},r=await n(e.arguments,t);return{result:this.normalizeToolResultV2(r)}}catch(e){return{result:{textResultForLlm:`Invoking this tool produced an error. Detailed information is not available.`,resultType:`failure`,error:e instanceof Error?e.message:String(e),toolTelemetry:{}}}}}async handlePermissionRequestV2(e){if(!e||typeof e.sessionId!=`string`||!e.permissionRequest)throw Error(`Invalid permission request payload`);let t=this.sessions.get(e.sessionId);if(!t)throw Error(`Session not found: ${e.sessionId}`);try{return{result:await t._handlePermissionRequestV2(e.permissionRequest)}}catch{return{result:{kind:`denied-no-approval-rule-and-could-not-request-from-user`}}}}normalizeToolResultV2(e){return e==null?{textResultForLlm:`Tool returned no result`,resultType:`failure`,error:`tool returned no result`,toolTelemetry:{}}:this.isToolResultObject(e)?e:{textResultForLlm:typeof e==`string`?e:JSON.stringify(e),resultType:`success`,toolTelemetry:{}}}isToolResultObject(e){return typeof e==`object`&&!!e&&`textResultForLlm`in e&&typeof e.textResultForLlm==`string`&&`resultType`in e}async reconnect(){this.state=`disconnected`;try{await this.stop(),await this.start()}catch{}}};function Z(e,t){return{name:e,...t}}const gr=()=>({kind:`approved`});function _r(e){return e.status===`renamed`&&e.oldPath!==void 0}function vr(e,t){return t===`head`?e.path:_r(e)?e.oldPath:e.path}function yr(e){let t=new Map,n=new Map;for(let r of e)t.set(r.path,r),_r(r)&&n.set(r.oldPath,(n.get(r.oldPath)??0)+1);for(let r of e)_r(r)&&n.get(r.oldPath)===1&&t.set(r.oldPath,r);return t}function br(e,t){let n=t.get(e.path);if(!n)return{error:`The file ${e.path} is not one of the reviewed files.`};let r=[],i=e;if(e.path!==n.path&&(i={...i,path:n.path},r.push(`normalized path from ${e.path} to ${n.path}`)),i.line>0&&!n.changedLines.includes(i.line)){let e=i.line;i={...i,line:0},r.push(`requested line ${e} is not a changed line in ${n.path}; stored as a file-level annotation`)}return r.length>0?{normalizedDraft:i,note:`${r.join(`; `)}.`}:{normalizedDraft:i}}const xr={low:1,medium:2,high:3},Sr={LOW:1,MEDIUM:2,HIGH:3};function Cr(e){return e.trim().replace(/\s+/g,` `)}const wr=p.object({path:p.string().min(1),line:p.number().int().min(0),severity:p.enum([`LOW`,`MEDIUM`,`HIGH`]),type:p.enum([`BUG`,`CODE_SMELL`,`VULNERABILITY`]),confidence:p.enum([`low`,`medium`,`high`]),title:p.string().min(1).max(200),details:p.string().max(1600).default(``),category:p.string().max(80).optional()}).transform(e=>w({path:e.path.trim(),line:e.line,severity:e.severity,type:e.type,confidence:e.confidence,title:Cr(e.title),details:Cr(e.details),category:e.category?Cr(e.category):void 0}));function Tr(e,t){return xr[e]>=xr[t]}function Er(e){return`finding-${f(`sha1`).update([e.path,String(e.line),e.severity,e.type,e.title,e.details].join(`|`)).digest(`hex`).slice(0,16)}`}function Dr(e,t,n,r){let i=yr(t),a=new Set,o=[];for(let t of e){let e=wr.safeParse(t);if(!e.success)continue;let n=e.data,s=i.get(n.path);if(!s)continue;let c=vr(s,`head`),l=c===n.path?n:{...n,path:c};if(l.line>0&&!s.changedLines.includes(l.line)||!Tr(l.confidence,r))continue;let u=[l.path,l.line,l.title.toLowerCase(),l.details.toLowerCase()].join(`|`);a.has(u)||(a.add(u),o.push({...l,externalId:Er(l)}))}return o.sort((e,t)=>{let n=Sr[t.severity]-Sr[e.severity];if(n!==0)return n;let r=xr[t.confidence]-xr[e.confidence];return r===0?[e.path,String(e.line),e.title].join(`:`).localeCompare([t.path,String(t.line),t.title].join(`:`)):r}),o.slice(0,n)}function Or(e){return e<=25}function kr(e){return e.trim().replace(/\s+/g,` `)}function Ar(e,t){if(!e)return;let n=kr(e);if(n.length!==0)return O(n,t,{preserveMaxLength:!0})}function jr(e,t,n=`${t}s`){return e===1?t:n}function Mr(e,t){return`+${e}/-${t}`}function Nr(e){return e.startsWith(`exceeds REVIEW_MAX_FILES limit`)?`max-files limit`:e.startsWith(`ignored path pattern (`)?`ignored path pattern`:e}function Pr(e){let t=Ar(e.pr.title,500),n=Ar(e.pr.description,500);return t&&n&&n.toLowerCase()!==t.toLowerCase()?O(`${t}. ${n}`,500,{preserveMaxLength:!0}):t||n||`Prepares ${e.pr.source.displayId} for merge into ${e.pr.target.displayId}.`}function Fr(e){let t=Mr(e.additions,e.deletions),n=`${e.changedLines.length} changed ${jr(e.changedLines.length,`line`)}`;switch(e.status){case`added`:return`Adds this file (${t}, ${n}).`;case`deleted`:return`Deletes this file (${t}, ${n}).`;case`renamed`:return`${e.oldPath?`Renamed from ${e.oldPath}`:`Renamed`}; updates ${n} (${t}).`;case`copied`:return`${e.oldPath?`Copied from ${e.oldPath}`:`Copied`}; updates ${n} (${t}).`;default:return`Updates ${n} (${t}).`}}function Ir(e){let t=Nr(e.reason);switch(e.status){case`added`:return t;case`deleted`:return t;case`renamed`:return e.oldPath?`renamed from ${e.oldPath}; ${t}`:t;case`copied`:return e.oldPath?`copied from ${e.oldPath}; ${t}`:t;default:return t}}function Lr(e,t){let n=Ar(t.prSummary,500)??Pr(e);if(!Or(e.reviewedFiles.length))return{prSummary:n,fileSummaries:[]};let r=yr(e.reviewedFiles),i=new Map;for(let e of t.fileSummaries){let t=r.get(e.path),n=Ar(e.summary,220);!t||!n||i.set(t.path,n)}return{prSummary:n,fileSummaries:e.reviewedFiles.map(e=>({path:e.path,summary:i.get(e.path)??Fr(e)}))}}function Rr(e=e=>import.meta.resolve(e)){let t;try{t=e(`@github/copilot/sdk`)}catch(e){throw Error(`Unable to resolve the bundled @github/copilot runtime. Ensure dependencies are installed before running the reviewer.`,{cause:e})}let n=v(_(_(ne(t))),`index.js`);if(!y(n))throw Error(`Resolved bundled @github/copilot CLI path does not exist: ${n}`);return n}const zr=[{type:`BUG`,hintClause:` for concrete defects`,promptDetails:`concrete correctness, data integrity, contract, state-transition, error-handling, or performance defects that can cause wrong results, crashes, corruption, stuck behavior, or broken compatibility.`},{type:`VULNERABILITY`,hintClause:` for concrete security issues`,promptDetails:`concrete security defects such as auth or authz bypass, injection, secret exposure, unsafe execution, trust-boundary violations, or unintended data disclosure.`},{type:`CODE_SMELL`,hintClause:` only for substantial merge-relevant fragility such as missing test coverage`,promptDetails:`only for substantial merge-relevant fragility with concrete impact, such as missing test coverage for a meaningful behavior change or brittle logic likely to break soon. Never use it for style, naming, formatting, or preference.`}];function Br(e){let[t,n,...r]=e;if(t===void 0)return``;if(n===void 0)return t;if(r.length===0)return`${t} and ${n}`;let i=r.pop();return i===void 0?`${t} and ${n}`:`${[t,n,...r].join(`, `)}, and ${i}`}const Vr=zr.map(e=>`- ${e.type}: ${e.promptDetails}`),Hr=`Use ${Br(zr.map(e=>`${e.type}${e.hintClause}`))}.`,Ur=`No question-shaped findings: verify or drop.`,Wr=[`- Missing or inadequate tests are reportable only when the gap materially weakens confidence in a meaningful behavior change, especially in auth, validation, persistence, or public API paths.`,`- Do not emit a standalone test-coverage finding when a stronger concrete BUG or VULNERABILITY already captures the same root cause unless the missing coverage leaves a distinct untested risk.`];function Gr(e,t){let n=Or(t.reviewedFiles.length),r=t.repoAgentsInstructions&&t.repoAgentsInstructions.length>0?[``,`Repository instructions from trusted AGENTS.md files:`,`<repo_agents_instructions>`,...t.repoAgentsInstructions.flatMap(e=>[`Path: ${e.path}`,`Applies to: ${e.appliesTo.join(`, `)}`,e.content,``]),`</repo_agents_instructions>`,`Treat these repository instructions as additional constraints unless they conflict with the review rules below. More specific nested AGENTS.md instructions override broader ones for matching paths.`]:[];return[`You are an elite code reviewer performing a high-signal review of a Bitbucket Data Center pull request.`,`Your job is to find all real, material issues introduced by this PR and ignore everything else.`,``,`<pull_request_context>`,`title: ${t.pr.title}`,`source_branch: ${t.pr.source.displayId}`,`target_branch: ${t.pr.target.displayId}`,`head_commit: ${t.headCommit}`,`merge_base_commit: ${t.mergeBaseCommit}`,`reviewed_files_available_through_tools: ${t.reviewedFiles.length}`,`skipped_files: ${t.skippedFiles.length}`,`per_file_summaries: ${n?`enabled`:`disabled (reviewed files exceed 25)`}`,`</pull_request_context>`,...r,``,`Mission:`,`- Find merge-blocking issues introduced by this PR.`,`- Focus on correctness, security/authz, data integrity, resource leaks, API contract breaks, and significant performance regressions in important paths.`,...Wr,`- Ignore style, formatting, naming, docs, import order, generic refactors, and preference-only feedback.`,`- Deprioritize generated artifacts such as lockfiles, snapshots, and regenerated API specs unless they reveal a concrete contract or publishing problem caused by the source change.`,`- No question-shaped or speculative findings: verify the code path or drop the concern.`,`- Cover the meaningful risk areas in reviewed files and continue after the first valid finding.`,``,`Evidence bar:`,`- Start from the diff.`,`- Read head and base when needed to confirm regressions, removed guards, renamed paths, or contract changes.`,`- Use get_related_file_content, get_related_tests, get_file_list_by_directory, search_text_in_repo, and search_symbol_name narrowly to validate concrete hypotheses or impacted paths. When scoping by path, pass concrete repo-relative directories as a directories array; wildcard directory patterns are not supported.`,`- Use get_file_diff_hunk to page large diffs.`,`- Treat CI as a clue, not proof. Never assume unverified behavior.`,``,`Review checklist:`,`- Correctness and invariants: validation, parsing, boundaries, null/empty/duplicate cases, state transitions, partial failures, off-by-one behavior, and head/base mismatches.`,`- Security and access control: authentication, authorization, secret or PII exposure, injection, path traversal, unsafe deserialization or dynamic execution, widened permissions, and trust-boundary mistakes.`,`- Data integrity and concurrency: transactions, retries, idempotency, ordering, cache invalidation, duplicate processing, races, locking, cleanup, and rollback behavior.`,`- Reliability and performance: error handling, timeouts, cancellation, resource leaks, unbounded work, hot-path regressions, repeated expensive operations, and blocking behavior in critical paths.`,`- Tests: for every non-trivial behavior change, verify positive, negative, and edge-case coverage at an appropriate level. If coverage is missing, only flag it when that gap creates a distinct merge-relevant risk.`,`- Prioritize files touching validation, auth, permissions, transactions, migrations, async flow, serialization, persistence, and public interfaces.`,``,`Finding taxonomy:`,...Vr,`- Prefer BUG or VULNERABILITY when the code is already wrong or already widens access.`,``,`Finding rules:`,n?`- Record exactly one PR-purpose summary with record_pr_summary, and one file summary with record_file_summary for every reviewed file you understand.`:`- Record exactly one PR-purpose summary with record_pr_summary. Per-file summaries are disabled when reviewed files exceed 25, so do not call record_file_summary for this review.`,`- Use emit_finding only for concrete validated issues. If a concern is still a question, investigate more or drop it.`,`- Use list_recorded_findings before adding more if you need to avoid duplicates or confirm coverage; use replace_recorded_finding to strengthen a draft or remove_recorded_finding to drop a weak one.`,`- Emit one finding per root cause. The path must be a reviewed file; skipped files are never valid targets.`,`- Prefer a changed head-side line. Use line 0 only for a true file-level issue that cannot be pinned to one changed line.`,`- Keep titles short. In details, explain the trigger, impact, and why the current code is wrong.`,`- Choose severity, type, and confidence conservatively.`,`- Emit as many distinct validated findings as needed, up to ${e.review.maxFindings}, and only if they meet ${e.review.minConfidence} confidence or better.`,``,`Recommended workflow:`,`1. Call get_pr_overview first to understand the PR, changed files, file summaries, and CI context.`,`2. Call list_changed_files only if you need a refreshed file list or skipped-file details beyond the overview.`,`3. Use get_file_diff on a suspicious file; if the diff is truncated, page with get_file_diff_hunk.`,`4. Use get_file_content on head and base as needed to verify the exact behavioral change.`,`5. Use get_related_tests before broad repo search when you need likely nearby coverage, and otherwise use related-file and search tools narrowly to validate cross-file assumptions.`,n?`6. As you confirm intent, call record_pr_summary once and record_file_summary for each reviewed file.`:`6. As you confirm intent, call record_pr_summary once. Do not record per-file summaries when reviewed files exceed 25.`,`7. Use list_recorded_findings, replace_recorded_finding, or remove_recorded_finding when refining the final distinct set.`,`8. Call emit_finding for every validated distinct issue you find, then sanity-check coverage and end with a concise plain-text conclusion.`,``,`Final response:`,`- Return only a short plain-text summary, not JSON.`,`- Keep it to 2-4 sentences.`,`- State clearly whether you found any reportable issues at the configured confidence threshold.`,`- If you found issues, mention the count and the main risk areas. If not, say that no reportable issues were found after inspecting the diff and relevant context.`,`- Do not include tool transcripts, long evidence dumps, or hidden reasoning.`].join(`
|
|
30
|
+
`)}function Kr(e,t,n,r,i){return{config:e,context:t,git:n,drafts:r,summaryDrafts:i,reviewedFileMap:yr(t.reviewedFiles)}}function qr(e){if(e.length===0)return[];let t=[...new Set(e)].sort((e,t)=>e-t),n=[],r=t[0]??0,i=t[0]??0;for(let e=1;e<t.length;e+=1){let a=t[e];if(a!==void 0){if(a===i+1){i=a;continue}n.push({start:r,end:i}),r=a,i=a}}return n.push({start:r,end:i}),n}function Jr(e){return qr(e).map(e=>e.start===e.end?`${e.start}`:`${e.start}-${e.end}`).join(`, `)}const Yr=new Set([`.git`,`.next`,`.pnpm-store`,`.yarn`,`build`,`coverage`,`dist`,`node_modules`,`out`,`target`,`vendor`]),Xr=new Set([`package-lock.json`,`pnpm-lock.yaml`,`yarn.lock`,`gradle.lockfile`,`go.sum`,`uv.lock`]),Zr=new Set([`.bmp`,`.class`,`.dll`,`.dylib`,`.exe`,`.gif`,`.ico`,`.jar`,`.jpeg`,`.jpg`,`.lock`,`.min.css`,`.min.js`,`.pdf`,`.pem`,`.png`,`.p12`,`.pfx`,`.so`,`.svg`,`.ttf`,`.woff`,`.woff2`,`.zip`]),Qr=[/\.env($|\.)/i];function $r(e){let t=e.toLowerCase();for(let e of Zr)if(t.endsWith(e))return!0;return!1}function ei(e){return{include:!1,reason:e}}function ti(e){return{include:!0,...e}}function ni(e){let t=e.trim();if(t.length===0)return;let n=g.posix.normalize(t.replace(/\\/g,`/`));if(!(n===`.`||n===``)&&!(n.startsWith(`/`)||n===`..`||n.startsWith(`../`)))return n}function ri(e){if(e.split(`/`).some(e=>Yr.has(e)))return`generated or vendored path`;if(Qr.some(t=>t.test(e)))return`potential secret-bearing path`}function ii(e){let t=[];for(let n of e)t.some(e=>e===n||n.startsWith(`${e}/`))||(t=t.filter(e=>!e.startsWith(`${n}/`)),t.push(n));return t}function ai(e){if(!e||e.length===0)return ti({normalizedPaths:[]});let t=!1,n=[];for(let r of e){let e=r.trim();if(e===``||e===`.`){t=!0;continue}let i=ni(e);if(!i)return ei(`directory must be repo-relative and stay within the repository`);if(i.includes(`*`)||i.includes(`?`)||i.includes(`[`))return ei(`directory wildcards are not supported; pass concrete repo-relative directories as a directories array`);let a=ri(i);if(a)return ei(a);n.push(i)}return ti(t?{normalizedPaths:[]}:{normalizedPaths:ii(n)})}function oi(e){let t=ni(e);if(!t)return ei(`path must be repo-relative and stay within the repository`);let n=ri(t);if(n)return ei(n);let r=t.split(`/`),i=r[r.length-1]??t;return Xr.has(i)?ei(`lockfile`):$r(t)?ei(`binary or generated extension`):ti({normalizedPath:t})}function si(e){return{path:e.path,oldPath:e.oldPath,status:e.status,additions:e.additions,deletions:e.deletions,changedLineCount:e.changedLines.length,changedLineRanges:Jr(e.changedLines),hunks:e.hunks.map(e=>({newStart:e.newStart,newEnd:Math.max(e.newStart,e.newStart+Math.max(e.newLines,1)-1),header:e.header}))}}function ci(e,t){let n=e.patch.split(/\r?\n/),r=n.flatMap((e,t)=>/^@@ -/.test(e)?[t]:[]);if(r.length===0)return;let i=t-1;if(i<0||i>=r.length)return;let a=n.slice(0,r[0]),o=r[i],s=r[i+1]??n.length;return w({fileHeader:a.length>0?a.join(`
|
|
31
|
+
`).trimEnd():void 0,hunkPatch:n.slice(o,s).join(`
|
|
32
|
+
`).trimEnd()})}function li(e,t){return{files:e.slice(0,t),truncated:e.length>t,totalFiles:e.length}}function ui(e){return e.length>0?e:[`.`]}function di(e){let t=[],n=0;for(let r of e){if(!oi(r.path).include){n+=1;continue}t.push(r)}return{entries:t,filteredCount:n}}function fi(e,t){let n=e.trim();if(n.length!==0&&!(n.length>t)&&!(n.includes(`\0`)||/[\r\n]/.test(n)))return n}function pi(e,t){if(e!==void 0&&t!==void 0&&t<e)return`endLine (${t}) must be greater than or equal to startLine (${e}).`}async function mi(e,t,n){for(let r of n){let n=await e.getPathTypeAtCommit(t,r);if(!n)return{status:`not_found`,path:r};if(n!==`directory`)return{status:`not_directory`,path:r}}return{status:`ok`}}function hi(e,t,n=`file`){return{status:`not_found`,kind:n,path:e,version:t,message:`${n===`directory`?`Directory`:`File`} ${e} is not present in the ${t} revision.`}}function gi(e,t){return{status:`unavailable`,path:e,version:t,message:`File ${e} could not be read as UTF-8 text from the ${t} revision.`}}function _i(e,t){let n=e.length>t,r=O(e,t,{suffix:`
|
|
33
|
+
... truncated ...`});return{patch:r,truncated:n,returnedPatchChars:r.length}}function vi(e,t){let n=br(e,t);if(n.error)return n;let r=n.normalizedDraft;if(!r)return{error:`The file ${e.path} is not one of the reviewed files.`};let i=t.get(r.path);return i?r.line>0&&!i.changedLines.includes(r.line)?{error:`Line ${r.line} is not a changed line in ${r.path}. Valid changed line ranges: ${Jr(i.changedLines)}`}:n:{error:`The file ${r.path} is not one of the reviewed files.`}}function Q(e){return{textResultForLlm:e,resultType:`rejected`}}function yi(e,t,n,r,i,a){let o=e.split(/\r?\n/).length,s=Math.max(1,r??1);if(s>o)return{status:`out_of_range`,path:t,version:n,totalLines:o,message:`Requested startLine ${s} is beyond the end of ${t} (${o} lines).`};let c=s+a.defaultFileSliceLines-1,l=i??c,u=Math.min(o,l,s+a.maxFileSliceLines-1);return w({path:t,version:n,totalLines:o,returnedStartLine:s,returnedEndLine:u,content:de(e,s,u),note:u<o?`Content truncated. Request lines ${u+1}-${Math.min(o,u+a.defaultFileSliceLines)} if you need more.`:void 0})}function bi(e){let{drafts:t,reviewedFileMap:n}=e;return Z(`emit_finding`,{description:`Record a validated review finding for later publication to Bitbucket Code Insights.`,parameters:{type:`object`,additionalProperties:!1,properties:{path:{type:`string`,description:`Reviewed file path in the current commit.`},line:{type:`integer`,minimum:0,description:`Head-side line number. Use 0 only for a file-level issue.`},severity:{type:`string`,enum:[`LOW`,`MEDIUM`,`HIGH`]},type:{type:`string`,enum:[`BUG`,`CODE_SMELL`,`VULNERABILITY`]},confidence:{type:`string`,enum:[`low`,`medium`,`high`]},title:{type:`string`,description:`A short issue title.`},details:{type:`string`,description:`A concise explanation of why this is an issue.`},category:{type:`string`,description:`Optional category such as security, correctness, or performance.`}},required:[`path`,`line`,`severity`,`type`,`confidence`,`title`,`details`]},handler:async e=>{let r=wr.safeParse(e);if(!r.success)return Q(`Invalid finding payload: ${r.error.message}`);let i=r.data,a=vi(i,n);if(a.error)return Q(a.error);let o=a.normalizedDraft??i;t.push(o);let s=o.line>0?`${o.path}:${o.line}`:`${o.path}:file`;return a.note?`Recorded finding ${t.length} for ${s}; ${a.note}`:`Recorded finding ${t.length} for ${s}.`}})}function xi(e){let{context:t}=e;return Z(`get_ci_summary`,{description:`Get the optional CI summary text produced earlier in the Jenkins pipeline.`,handler:async()=>w({status:t.ciSummary?`ok`:`missing`,ciSummary:t.ciSummary,message:t.ciSummary?void 0:`No CI summary was provided.`})})}const Si=p.object({path:p.string().min(1),version:p.enum([`head`,`base`]),startLine:p.number().int().min(1).optional(),endLine:p.number().int().min(1).optional()}).strict();function Ci(e){let{config:t,context:n,git:r,reviewedFileMap:i}=e;return Z(`get_file_content`,{description:`Get head or base file contents with line numbers for a reviewed file.`,parameters:{type:`object`,additionalProperties:!1,properties:{path:{type:`string`,description:`Path of the reviewed file.`},version:{type:`string`,enum:[`head`,`base`],description:`Which revision to read.`},startLine:{type:`integer`,minimum:1,description:`1-based start line.`},endLine:{type:`integer`,minimum:1,description:`1-based end line.`}},required:[`path`,`version`]},handler:async e=>{let a=Si.safeParse(e);if(!a.success)return Q(`Invalid file-content payload: ${a.error.message}`);let o=i.get(a.data.path);if(!o)return Q(`The file ${a.data.path} is not available for review. Use list_changed_files first.`);let s=pi(a.data.startLine,a.data.endLine);if(s)return Q(s);let c=a.data.version===`head`?n.headCommit:n.mergeBaseCommit,l=vr(o,a.data.version),u=await r.readTextFileAtCommit(c,l);return u.status===`not_found`?hi(l,a.data.version):u.status===`not_text`?gi(l,a.data.version):u.status===`ok`?yi(u.content,l,a.data.version,a.data.startLine,a.data.endLine,t.review):Q(`The path ${l} is not a readable file in the ${a.data.version} revision.`)}})}function wi(e){let{config:t,reviewedFileMap:n}=e;return Z(`get_file_diff`,{description:`Get the unified diff for a specific reviewed file.`,parameters:{type:`object`,additionalProperties:!1,properties:{path:{type:`string`,description:`Path of the reviewed file.`}},required:[`path`]},handler:async e=>{let r=n.get(e.path);return r?{...si(r),..._i(r.patch,t.review.maxPatchChars)}:Q(`The file ${e.path} is not available for review. Use list_changed_files first.`)}})}function Ti(e){let{config:t,reviewedFileMap:n}=e;return Z(`get_file_diff_hunk`,{description:`Get a specific diff hunk for a reviewed file, including file header context.`,parameters:{type:`object`,additionalProperties:!1,properties:{path:{type:`string`,description:`Path of the reviewed file.`},hunkIndex:{type:`integer`,minimum:1,description:`1-based diff hunk index to return.`}},required:[`path`,`hunkIndex`]},handler:async e=>{let r=n.get(e.path);if(!r)return Q(`The file ${e.path} is not available for review. Use list_changed_files first.`);let i=ci(r,e.hunkIndex);if(!i){let t=r.hunks.length>0?`1-${r.hunks.length}`:`none`;return Q(`Hunk ${e.hunkIndex} is not available for ${e.path}. Valid hunk indexes: ${t}`)}return{...si(r),hunkIndex:e.hunkIndex,totalHunks:r.hunks.length,fileHeader:i.fileHeader,..._i(i.hunkPatch,t.review.maxPatchChars)}}})}const Ei=p.object({directories:p.array(p.string()).max(50).optional(),version:p.enum([`head`,`base`]),limit:p.number().int().min(1).optional()}).strict();function Di(e){let{context:t,git:n}=e;return Z(`get_file_list_by_directory`,{description:`List repo files under a safe directory at the head or base revision for architectural context.`,parameters:{type:`object`,additionalProperties:!1,properties:{directories:{type:`array`,items:{type:`string`},description:`Repo-relative directories. Use ['.'] or omit for the repo root.`},version:{type:`string`,enum:[`head`,`base`],description:`Which revision to inspect.`},limit:{type:`integer`,minimum:1,maximum:200,description:`Maximum number of paths to return.`}},required:[`version`]},handler:async e=>{let r=Ei.safeParse(e);if(!r.success)return Q(`Invalid directory-list payload: ${r.error.message}`);let i=ai(r.data.directories);if(!i.include)return Q(`Directory access rejected: ${i.reason}`);let a=r.data.version===`head`?t.headCommit:t.mergeBaseCommit,o=await mi(n,a,i.normalizedPaths);if(o.status===`not_found`)return Q(`Directory access rejected: ${o.path} is not present in the ${r.data.version} revision.`);if(o.status===`not_directory`)return Q(`Directory access rejected: ${o.path} is a file, not a directory.`);let s=di((await n.listFilesAtCommit(a,i.normalizedPaths)).map(e=>({path:e}))),c=Math.min(200,Math.max(1,r.data.limit??50)),l=li(s.entries.map(e=>e.path),c);return{directories:ui(i.normalizedPaths),version:r.data.version,filteredFileCount:s.filteredCount,files:l.files,truncated:l.truncated||s.filteredCount>0,totalFiles:l.totalFiles}}})}function Oi(e){let{context:t}=e;return Z(`get_pr_overview`,{description:`Get pull request metadata, diff statistics, and CI summary.`,handler:async()=>w({title:t.pr.title,description:t.pr.description,sourceBranch:t.pr.source.displayId,targetBranch:t.pr.target.displayId,headCommit:t.headCommit,mergeBaseCommit:t.mergeBaseCommit,diffStats:t.diffStats,reviewedFiles:t.reviewedFiles.map(e=>si(e)),skippedFiles:t.skippedFiles,ciSummary:w({status:t.ciSummary?`ok`:`missing`,content:t.ciSummary,message:t.ciSummary?void 0:`No CI summary was provided.`})})})}const ki=p.object({path:p.string().min(1),version:p.enum([`head`,`base`]),startLine:p.number().int().min(1).optional(),endLine:p.number().int().min(1).optional()}).strict();function Ai(e){let{config:t,context:n,git:r}=e;return Z(`get_related_file_content`,{description:`Read a safe repo-relative file outside the changed set for nearby architectural context.`,parameters:{type:`object`,additionalProperties:!1,properties:{path:{type:`string`,description:`Repo-relative file path at head or base.`},version:{type:`string`,enum:[`head`,`base`],description:`Which revision to read.`},startLine:{type:`integer`,minimum:1,description:`1-based start line.`},endLine:{type:`integer`,minimum:1,description:`1-based end line.`}},required:[`path`,`version`]},handler:async e=>{let i=ki.safeParse(e);if(!i.success)return Q(`Invalid related-file payload: ${i.error.message}`);let a=oi(i.data.path);if(!a.include)return Q(`Related file access rejected: ${a.reason}`);let o=pi(i.data.startLine,i.data.endLine);if(o)return Q(o);let s=i.data.version===`head`?n.headCommit:n.mergeBaseCommit,c=await r.readTextFileAtCommit(s,a.normalizedPath);return c.status===`not_found`?hi(a.normalizedPath,i.data.version):c.status===`not_text`?gi(a.normalizedPath,i.data.version):c.status===`not_file`?Q(`Related file access rejected: ${a.normalizedPath} is a directory, not a file.`):yi(c.content,a.normalizedPath,i.data.version,i.data.startLine,i.data.endLine,t.review)}})}const ji=new Set([`src`,`main`,`java`,`kotlin`,`scala`,`groovy`,`ts`,`tsx`,`js`,`jsx`,`test`,`tests`,`spec`,`specs`,`lib`,`api`,`com`,`org`,`net`]),Mi=/(^|\/)(test|tests|__tests__)($|\/)/i,Ni=p.object({path:p.string().min(1),version:p.enum([`head`,`base`]).optional(),limit:p.number().int().min(1).max(100).optional()}).strict();function Pi(e){return Mi.test(e)?!0:/\.(test|spec)\.[^/]+$/i.test(e)||/(?:^|\/)[^/]+Tests?\.[^/]+$/i.test(e)}function Fi(e){let[t]=e.split(/\.[^/.]+$/);return t?t.split(`/`).flatMap(e=>e.split(/[^A-Za-z0-9]+/)).flatMap(e=>e.split(/(?=[A-Z][a-z])/)).map(e=>e.trim().toLowerCase()).filter(e=>e.length>=3).filter(e=>!ji.has(e)):[]}function Ii(e,t){let n=e.toLowerCase(),r=0;for(let e of t)n.includes(e)&&(r+=e.length);return r}function Li(e,t){let n=Ii(e,t),r=n;return Mi.test(e)&&(r+=5),/\.(test|spec)\.[^/]+$/i.test(e)&&(r+=4),/(?:^|\/)[^/]+Tests?\.[^/]+$/i.test(e)&&(r+=4),{tokenScore:n,score:r}}function Ri(e){return[...new Set(e)]}function zi(e,t){let n=vr(e,t).split(`/`),r=[];for(let e=n.length-1;e>=1;--e){let t=n.slice(0,e).join(`/`);t.length>0&&r.push(t)}let i=n[0];return i&&i!==`src`&&r.push(i),r.push(`test`,`tests`),Ri(r)}function Bi(e){let{context:t,git:n,reviewedFileMap:r}=e;return Z(`get_related_tests`,{description:`Suggest likely nearby automated tests for a reviewed file by scanning concrete directories at head or base.`,parameters:{type:`object`,additionalProperties:!1,properties:{path:{type:`string`,description:`Path of the reviewed file to find related tests for.`},version:{type:`string`,enum:[`head`,`base`],description:`Which revision to inspect for candidate tests.`},limit:{type:`integer`,minimum:1,maximum:100,description:`Maximum candidate test files to return.`}},required:[`path`]},handler:async e=>{let i=Ni.safeParse(e);if(!i.success)return Q(`Invalid related-tests payload: ${i.error.message}`);let a=r.get(i.data.path);if(!a)return Q(`The file ${i.data.path} is not available for review. Use list_changed_files first.`);let o=i.data.version??`head`,s=o===`head`?t.headCommit:t.mergeBaseCommit,c=zi(a,o),l=[];for(let e of c){if(await n.getPathTypeAtCommit(s,e)!==`directory`)continue;let t=await n.listFilesAtCommit(s,[e]);for(let e of t)Pi(e)&&l.push(e)}let u=Fi(vr(a,o)),d=i.data.limit??20,f=Ri(l).map(e=>({path:e,...Li(e,u)})).filter(e=>e.score>0&&(u.length===0||e.tokenScore>0)).sort((e,t)=>t.score-e.score||e.path.localeCompare(t.path)).slice(0,d);return w({path:i.data.path,version:o,directoriesSearched:c,candidateCount:f.length,candidates:f.map(e=>({path:e.path,score:e.score})),note:f.length===0?O(`No likely related tests were found in nearby concrete directories. If coverage still matters, search more narrowly with search_text_in_repo or inspect known test roots.`,240):void 0})}})}function Vi(e){let{context:t}=e;return Z(`list_changed_files`,{description:`List the changed files available for review, with status and changed line ranges.`,parameters:{type:`object`,additionalProperties:!1,properties:{includeSkipped:{type:`boolean`,description:`Include skipped files and the reason they were skipped.`}}},handler:async e=>w({reviewedFiles:t.reviewedFiles.map(e=>si(e)),skippedFiles:e.includeSkipped?t.skippedFiles:void 0})})}function Hi(e){let{drafts:t}=e;return Z(`list_recorded_findings`,{description:`List the currently recorded finding drafts so the reviewer can avoid duplicates or replace weaker findings.`,handler:async()=>({count:t.length,findings:t.map((e,t)=>({findingNumber:t+1,...e}))})})}const Ui=p.object({path:p.string().min(1),summary:p.string().min(1).max(500)});function Wi(e){let{context:t,summaryDrafts:n,reviewedFileMap:r}=e;return Z(`record_file_summary`,{description:`Record a concise summary of what changed in one reviewed file.`,parameters:{type:`object`,additionalProperties:!1,properties:{path:{type:`string`,description:`Reviewed file path in the current commit.`},summary:{type:`string`,description:`One sentence describing the meaningful behavior or code change in this file.`}},required:[`path`,`summary`]},handler:async e=>{if(!Or(t.reviewedFiles.length))return Q(`Per-file summaries are disabled when reviewed files exceed 25.`);let i=Ui.safeParse(e);if(!i.success)return Q(`Invalid file summary payload: ${i.error.message}`);let a=r.get(i.data.path);if(!a)return Q(`The file ${i.data.path} is not one of the reviewed files.`);let o=n.fileSummaries.findIndex(e=>e.path===a.path),s={path:a.path,summary:i.data.summary};return o>=0?(n.fileSummaries[o]=s,`Updated the summary for ${a.path}.`):(n.fileSummaries.push(s),`Recorded the summary for ${a.path}.`)}})}const Gi=p.object({summary:p.string().min(1).max(1e3)});function Ki(e){let{summaryDrafts:t}=e;return Z(`record_pr_summary`,{description:`Record a concise plain-language summary of what the pull request is trying to do.`,parameters:{type:`object`,additionalProperties:!1,properties:{summary:{type:`string`,description:`One or two sentences describing the PR's purpose and main behavior change.`}},required:[`summary`]},handler:async e=>{let n=Gi.safeParse(e);return n.success?(t.prSummary=n.data.summary,`Recorded the pull request summary.`):Q(`Invalid PR summary payload: ${n.error.message}`)}})}function qi(e){let{drafts:t}=e;return Z(`remove_recorded_finding`,{description:`Remove a previously recorded finding draft that is duplicate, too weak, or superseded.`,parameters:{type:`object`,additionalProperties:!1,properties:{findingNumber:{type:`integer`,minimum:1,description:`1-based finding number from list_recorded_findings.`}},required:[`findingNumber`]},handler:async e=>{let n=e.findingNumber-1;if(n<0||n>=t.length)return Q(`Finding ${e.findingNumber} does not exist. Recorded findings: ${t.length}.`);let r=t.splice(n,1)[0];return r?`Removed finding ${e.findingNumber} for ${r.path}:${r.line}. Remaining findings: ${t.length}.`:Q(`Finding ${e.findingNumber} could not be removed.`)}})}function Ji(e){let{drafts:t,reviewedFileMap:n}=e;return Z(`replace_recorded_finding`,{description:`Replace an already recorded finding draft with a stronger or more accurate one.`,parameters:{type:`object`,additionalProperties:!1,properties:{findingNumber:{type:`integer`,minimum:1,description:`1-based finding number from list_recorded_findings.`},path:{type:`string`,description:`Reviewed file path in the current commit.`},line:{type:`integer`,minimum:0,description:`Head-side line number. Use 0 only for a file-level issue.`},severity:{type:`string`,enum:[`LOW`,`MEDIUM`,`HIGH`]},type:{type:`string`,enum:[`BUG`,`CODE_SMELL`,`VULNERABILITY`]},confidence:{type:`string`,enum:[`low`,`medium`,`high`]},title:{type:`string`,description:`A short issue title.`},details:{type:`string`,description:`A concise explanation of why this is an issue.`},category:{type:`string`,description:`Optional category such as security, correctness, or performance.`}},required:[`findingNumber`,`path`,`line`,`severity`,`type`,`confidence`,`title`,`details`]},handler:async e=>{let r=e.findingNumber-1;if(r<0||r>=t.length)return Q(`Finding ${e.findingNumber} does not exist. Recorded findings: ${t.length}.`);let i=wr.safeParse(e);if(!i.success)return Q(`Invalid finding payload: ${i.error.message}`);let a=i.data,o=vi(a,n);if(o.error)return Q(o.error);let s=o.normalizedDraft??a;t[r]=s;let c=s.line>0?`${s.path}:${s.line}`:`${s.path}:file`;return o.note?`Replaced finding ${e.findingNumber} with ${c}; ${o.note}`:`Replaced finding ${e.findingNumber} with ${c}.`}})}function Yi(e){return e.replace(/^"|"$/g,``).replace(/\\/g,`/`)}function Xi(e){let t=/^diff --git "?a\/(.+?)"? "?b\/(.+?)"?$/.exec(e);if(t)return{oldPath:Yi(t[1]??``),newPath:Yi(t[2]??``)}}function Zi(e){let{currentHunk:t}=e;t&&(e.hunks.push({oldStart:t.oldStart,oldLines:t.oldLines,newStart:t.newStart,newLines:t.newLines,header:t.header,changedLines:[...new Set(t.changedLines)].sort((e,t)=>e-t)}),delete e.currentHunk)}function Qi(e){if(e)return Zi(e),w({path:e.path,oldPath:e.oldPath,status:e.status,patch:e.patchLines.join(`
|
|
34
|
+
`).trimEnd(),changedLines:[...e.changedLineSet].sort((e,t)=>e-t),hunks:e.hunks,additions:e.additions,deletions:e.deletions,isBinary:e.isBinary})}function $i(e){let t=[],n=e.length>0?e.split(/\r?\n/):[],r;for(let e of n){if(e.startsWith(`diff --git `)){let n=Qi(r);n&&t.push(n);let i=Xi(e);if(!i){r=void 0;continue}r=w({path:i.newPath,oldPath:i.oldPath===i.newPath?void 0:i.oldPath,status:`modified`,patchLines:[e],changedLineSet:new Set,hunks:[],additions:0,deletions:0,isBinary:!1});continue}if(!r)continue;if(r.patchLines.push(e),e.startsWith(`new file mode `)){r.status=`added`;continue}if(e.startsWith(`deleted file mode `)){r.status=`deleted`;continue}if(e.startsWith(`rename from `)){r.status=`renamed`,r.oldPath=Yi(e.slice(12));continue}if(e.startsWith(`rename to `)){r.path=Yi(e.slice(10));continue}if(e.startsWith(`copy from `)){r.status=`copied`,r.oldPath=Yi(e.slice(10));continue}if(e.startsWith(`copy to `)){r.path=Yi(e.slice(8));continue}if(e.startsWith(`Binary files `)){r.isBinary=!0;continue}let n=/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/.exec(e);if(n){Zi(r),r.currentHunk={oldStart:Number.parseInt(n[1]??`0`,10),oldLines:Number.parseInt(n[2]||`1`,10),newStart:Number.parseInt(n[3]??`0`,10),newLines:Number.parseInt(n[4]||`1`,10),header:(n[5]??``).trim(),changedLines:[],nextOldLine:Number.parseInt(n[1]??`0`,10),nextNewLine:Number.parseInt(n[3]??`0`,10)};continue}let i=r.currentHunk;if(i){if(e.startsWith(`+`)&&!e.startsWith(`+++`)){r.additions+=1,r.changedLineSet.add(i.nextNewLine),i.changedLines.push(i.nextNewLine),i.nextNewLine+=1;continue}if(e.startsWith(`-`)&&!e.startsWith(`---`)){r.deletions+=1,i.nextOldLine+=1;continue}e.startsWith(` `)&&(i.nextOldLine+=1,i.nextNewLine+=1)}}let i=Qi(r);return i&&t.push(i),{files:t,stats:t.reduce((e,t)=>({fileCount:e.fileCount+1,additions:e.additions+t.additions,deletions:e.deletions+t.deletions}),{fileCount:0,additions:0,deletions:0})}}function ea(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function ta(e){return`(^|[^A-Za-z0-9_])${ea(e)}([^A-Za-z0-9_]|$)`}const na=p.object({symbol:p.string(),version:p.enum([`head`,`base`]),directories:p.array(p.string()).max(50).optional(),limit:p.number().int().min(1).optional()}).strict();function ra(e){let{context:t,git:n}=e;return Z(`search_symbol_name`,{description:`Search for a likely identifier or symbol name across repo files at the head or base revision.`,parameters:{type:`object`,additionalProperties:!1,properties:{symbol:{type:`string`,description:`Identifier or symbol name to search for.`},version:{type:`string`,enum:[`head`,`base`],description:`Which revision to search.`},directories:{type:`array`,items:{type:`string`},description:`Optional repo-relative directories to search. Omit or use ['.'] for the repo root.`},limit:{type:`integer`,minimum:1,maximum:200,description:`Maximum matches to return.`}},required:[`symbol`,`version`]},handler:async e=>{let r=na.safeParse(e);if(!r.success)return Q(`Invalid symbol-search payload: ${r.error.message}`);let i=fi(r.data.symbol,120);if(!i)return Q(`Symbol query must be non-empty, single-line, and at most 120 characters.`);let a=ai(r.data.directories);if(!a.include)return Q(`Directory access rejected: ${a.reason}`);let o=r.data.version===`head`?t.headCommit:t.mergeBaseCommit,s=await mi(n,o,a.normalizedPaths);if(s.status===`not_found`)return Q(`Directory access rejected: ${s.path} is not present in the ${r.data.version} revision.`);if(s.status===`not_directory`)return Q(`Directory access rejected: ${s.path} is a file, not a directory.`);let c;try{c=await n.searchTextAtCommit(o,ta(i),{directoryPaths:a.normalizedPaths,limit:Math.min(200,Math.max(1,r.data.limit??50)),mode:`regex`})}catch(e){return Q(`Symbol search execution failed: ${e.message}`)}let l=di(c.matches),u=Math.min(200,Math.max(1,r.data.limit??50)),d=l.entries.slice(0,u),f=c.truncated?Math.max(l.entries.length,c.totalMatches-l.filteredCount):l.entries.length;return{symbol:i,version:r.data.version,directories:ui(a.normalizedPaths),matches:d,truncated:c.truncated||l.entries.length>d.length||l.filteredCount>0,totalMatches:l.entries.length,unfilteredMatchCount:c.totalMatches,filteredMatchCount:l.filteredCount,safeTotalMatches:f}}})}const ia=p.object({query:p.string(),version:p.enum([`head`,`base`]),directories:p.array(p.string()).max(50).optional(),mode:p.enum([`literal`,`regex`]).optional(),wholeWord:p.boolean().optional(),limit:p.number().int().min(1).optional()}).strict();function aa(e){try{new RegExp(e,`u`);return}catch(e){return e.message}}function oa(e){let{context:t,git:n}=e;return Z(`search_text_in_repo`,{description:`Search repo files at the head or base revision for literal or regex text matches within safe directories.`,parameters:{type:`object`,additionalProperties:!1,properties:{query:{type:`string`,description:`Literal text or regex pattern to search for.`},version:{type:`string`,enum:[`head`,`base`],description:`Which revision to search.`},directories:{type:`array`,items:{type:`string`},description:`Optional repo-relative directories to search. Omit or use ['.'] for the repo root.`},mode:{type:`string`,enum:[`literal`,`regex`],description:`Search mode.`},wholeWord:{type:`boolean`,description:`Whole-word matching for literal search.`},limit:{type:`integer`,minimum:1,maximum:200,description:`Maximum matches to return.`}},required:[`query`,`version`]},handler:async e=>{let r=ia.safeParse(e);if(!r.success)return Q(`Invalid search payload: ${r.error.message}`);let i=fi(r.data.query,200);if(!i)return Q(`Search query must be non-empty, single-line, and at most 200 characters.`);let a=r.data.mode??`literal`;if(a===`regex`){let e=aa(i);if(e)return Q(`Invalid regex search pattern: ${e}`)}if(a===`regex`&&r.data.wholeWord)return Q(`wholeWord is only supported for literal searches.`);let o=ai(r.data.directories);if(!o.include)return Q(`Directory access rejected: ${o.reason}`);let s=r.data.version===`head`?t.headCommit:t.mergeBaseCommit,c=await mi(n,s,o.normalizedPaths);if(c.status===`not_found`)return Q(`Directory access rejected: ${c.path} is not present in the ${r.data.version} revision.`);if(c.status===`not_directory`)return Q(`Directory access rejected: ${c.path} is a file, not a directory.`);let l=w({directoryPaths:o.normalizedPaths,limit:Math.min(200,Math.max(1,r.data.limit??50)),mode:a,wholeWord:a===`regex`?!1:r.data.wholeWord}),u;try{u=await n.searchTextAtCommit(s,i,l)}catch(e){return Q(`Search execution failed: ${e.message}`)}let d=di(u.matches),f=l.limit??50,p=d.entries.slice(0,f),m=u.truncated?Math.max(d.entries.length,u.totalMatches-d.filteredCount):d.entries.length;return{query:i,version:r.data.version,mode:a,wholeWord:a===`regex`?!1:!!r.data.wholeWord,directories:ui(o.normalizedPaths),matches:p,truncated:u.truncated||d.entries.length>p.length||d.filteredCount>0,totalMatches:d.entries.length,unfilteredMatchCount:u.totalMatches,filteredMatchCount:d.filteredCount,safeTotalMatches:m}}})}const sa=[`get_pr_overview`,`list_changed_files`,`get_file_diff`,`get_file_diff_hunk`,`get_file_content`,`get_file_list_by_directory`,`get_related_file_content`,`get_related_tests`,`search_text_in_repo`,`search_symbol_name`,`get_ci_summary`,`record_pr_summary`,`record_file_summary`,`list_recorded_findings`,`remove_recorded_finding`,`replace_recorded_finding`,`emit_finding`];function ca(e,t,n,r,i){let a=Kr(e,t,n,r,i);return[Oi(a),Vi(a),wi(a),Ti(a),Ci(a),Di(a),Ai(a),Bi(a),oa(a),ra(a),xi(a),Ki(a),Wi(a),Hi(a),qi(a),Ji(a),bi(a)]}function la(e,t){let n=new Map,r=(e,t)=>{t&&n.set(e,`${n.get(e)??``}${t}`)},i=(e,r)=>{let i=(n.get(e)??``)||(r??``);n.delete(e),i&&t.trace(`copilot reasoning`,{reasoningId:e,content:i})};e.on(`assistant.reasoning_delta`,e=>{r(e.data.reasoningId,e.data.deltaContent)}),e.on(`assistant.reasoning`,e=>{i(e.data.reasoningId,e.data.content)}),e.on(`session.idle`,()=>{for(let e of n.keys())i(e)})}function ua(e){return sa.includes(e)}function da(e,t){return[`Review all material issues introduced by this pull request.`,`Inspect diff plus relevant head/base code before emitting any finding.`,`Only treat missing tests as a standalone finding when the gap materially reduces confidence in a risky behavior change; prefer concrete BUG or VULNERABILITY findings when the code is already wrong.`,`Ignore style, naming, formatting, and preference-only feedback.`,Hr,Ur,...Or(t)?[]:[`Per-file summaries are disabled for large reviews with more than 25 reviewed files; keep the PR summary current and continue reviewing without file summaries.`],`Cover the reviewed risk areas and continue after the first finding when more distinct issues may exist.`,`Keep findings distinct, evidence-backed, and limited to ${e.review.minConfidence} confidence or better, up to ${e.review.maxFindings} total.`].join(` `)}function fa(e,t){let n=Or(t);switch(e){case`get_pr_overview`:return`Use the overview to scope the review, find the highest-risk files, and avoid redundant file-list or CI calls unless you need more detail.`;case`list_changed_files`:return`Use this only when you need a refreshed file list or skipped-file details beyond get_pr_overview; then start with the riskiest reviewed files and continue until meaningful reviewed changes are covered.`;case`get_file_diff`:return`Study the exact changed lines and look for removed guards, altered control flow, or contract shifts.`;case`get_file_diff_hunk`:return`Use hunk paging to inspect a large diff without broadening scope beyond the file under review.`;case`get_file_content`:return`Read head and base content as needed to verify a concrete regression, broken invariant, or API change.`;case`get_file_list_by_directory`:return`Use directory listing to orient around nearby code, but keep the review anchored to PR-introduced behavior.`;case`get_related_file_content`:return`Read nearby files to confirm concrete hypotheses about impact, invariants, call paths, or additional affected paths.`;case`get_related_tests`:return`Use this to find likely nearby automated tests for a reviewed file before resorting to broader repository search.`;case`search_text_in_repo`:case`search_symbol_name`:return`Search narrowly to validate suspected code paths, impacted call sites, or nearby tests. Avoid broad repo fishing expeditions and wildcard-like directory guesses.`;case`get_ci_summary`:return`Treat CI output as a prioritization hint, not proof of a reportable issue.`;case`record_pr_summary`:return n?`Capture the PR's intended behavior change in one concise, evidence-backed summary once you understand the diff.`:`Capture the PR's intended behavior change in one concise, evidence-backed summary once you understand the diff. Per-file summaries are disabled for reviews with more than 25 reviewed files.`;case`record_file_summary`:return n?`Record a short, concrete summary of what changed in a reviewed file once you have enough context to describe it accurately.`:`Per-file summaries are disabled for reviews with more than 25 reviewed files; do not use this tool.`;case`list_recorded_findings`:return`Check recorded findings before adding more to avoid duplicates and confirm whether important reviewed areas still lack coverage.`;case`remove_recorded_finding`:return`Remove a recorded finding only when it is duplicate, superseded, or too weak to keep in the final set.`;case`replace_recorded_finding`:return`Replace a recorded finding only when the new draft is clearly stronger, more accurate, or better located.`;case`emit_finding`:return`Only emit a finding after verifying the issue from inspected code. ${Hr} ${Ur} Use one finding per root cause, prefer a changed head-side line, and keep looking for additional distinct issues after recording one.`;default:return`Stay focused on distinct, evidence-backed issues introduced by the pull request.`}}function pa(e,t,n,r){let i=Or(r);switch(e){case`get_pr_overview`:return`Choose the most suspicious files from the overview, inspect their diffs, and only call list_changed_files or get_ci_summary if the overview left a concrete gap.`;case`list_changed_files`:return`Prioritize files touching validation, auth, persistence, async flow, serialization, and public interfaces; do not stop after one risky file.`;case`get_file_diff`:return`If the diff looks risky, confirm the exact behavior in head/base code before deciding whether an issue exists.`;case`get_file_diff_hunk`:return`Continue with the next relevant hunk or matching code context until the file's meaningful changed behavior is covered; do not scan the repo unnecessarily.`;case`get_file_content`:return`Do not emit a finding unless the inspected code shows a concrete, material issue introduced by the PR, and keep checking for other distinct issues after confirming one.`;case`get_file_list_by_directory`:case`get_related_file_content`:case`get_related_tests`:case`search_text_in_repo`:case`search_symbol_name`:return`Use this context to confirm or reject a specific hypothesis, then move to the next uncovered risky path. If repeated searches are not sharpening the hypothesis, stop searching and decide based on the evidence you have.`;case`get_ci_summary`:return`CI may explain where to look next, but you still need code-level evidence before reporting anything.`;case`record_pr_summary`:return i?`Keep the PR summary concise and factual, then continue until each reviewed file also has a clear file-change summary.`:`Keep the PR summary concise and factual. Per-file summaries are disabled for reviews with more than 25 reviewed files, so continue reviewing without recording them.`;case`record_file_summary`:return i?`Keep file summaries concrete and per-file; continue until all reviewed files have coverage.`:`Per-file summaries are disabled for reviews with more than 25 reviewed files; continue reviewing without recording them.`;case`list_recorded_findings`:return`Recorded findings: ${t}/${n.maxFindings}. Avoid duplicates, but continue looking if reviewed risky areas remain unchecked.`;case`remove_recorded_finding`:return`Recorded findings: ${t}/${n.maxFindings}. Keep only distinct issues, then continue covering remaining risky reviewed changes.`;case`replace_recorded_finding`:return`Recorded findings: ${t}/${n.maxFindings}. Keep the strongest distinct set without stopping the review early.`;case`emit_finding`:return t>=n.maxFindings?`You have reached the configured maximum of ${n.maxFindings} findings. Do not add more unless a clearly stronger issue replaces a weaker one.`:`Findings recorded: ${t}/${n.maxFindings}. Keep findings distinct and evidence-backed, then continue searching for additional validated issues.`;default:return`Keep findings distinct, evidence-backed, and continue until the reviewed risky changes have been covered.`}}function ma(e,t=Rr){let n=e.logLevel===`debug`?`debug`:`error`;return w({cwd:e.repoRoot,logLevel:n,cliPath:t()})}function ha(e){return O(e.replace(/\s+/g,` `).trim(),80,{suffix:`...`,preserveMaxLength:!0})}function ga(e){if(e instanceof Error)return ga(e.message);if(typeof e==`string`){let t=ha(e);return t.length===0?void 0:/[\s="]/.test(t)?JSON.stringify(t):t}if(typeof e==`number`||typeof e==`boolean`)return String(e)}function _a(e){return!e||typeof e!=`object`||Array.isArray(e)?{}:e}function va(e){return!e||typeof e!=`object`||Array.isArray(e)?{}:e}function ya(e){if(!Array.isArray(e))return;let t=e.filter(e=>typeof e==`string`).map(e=>ha(e)).filter(e=>e.length>0);if(t.length!==0)return t.join(`,`)}function ba(e,t){let n=_a(t),r=(e,t)=>{let n=ga(t);return n?`${e}=${n}`:void 0};switch(e){case`get_file_content`:case`get_related_file_content`:return[r(`path`,n.path),r(`version`,n.version),r(`start`,n.startLine),r(`end`,n.endLine)].filter(e=>e!==void 0);case`get_file_diff`:return[r(`path`,n.path)].filter(e=>e!==void 0);case`get_file_diff_hunk`:return[r(`path`,n.path),r(`hunk`,n.hunkIndex)].filter(e=>e!==void 0);case`get_file_list_by_directory`:return[r(`directories`,ya(n.directories)),r(`version`,n.version)].filter(e=>e!==void 0);case`search_text_in_repo`:return[r(`query_chars`,typeof n.query==`string`?n.query.length:void 0),r(`version`,n.version),r(`directories`,ya(n.directories)),r(`mode`,n.mode)].filter(e=>e!==void 0);case`search_symbol_name`:return[r(`symbol_chars`,typeof n.symbol==`string`?n.symbol.length:void 0),r(`version`,n.version),r(`directories`,ya(n.directories))].filter(e=>e!==void 0);case`record_pr_summary`:return[r(`summary_chars`,typeof n.summary==`string`?n.summary.length:void 0)].filter(e=>e!==void 0);case`record_file_summary`:return[r(`path`,n.path)].filter(e=>e!==void 0);case`remove_recorded_finding`:return[r(`finding`,n.findingNumber)].filter(e=>e!==void 0);case`replace_recorded_finding`:return[r(`finding`,n.findingNumber),r(`path`,n.path),r(`line`,n.line)].filter(e=>e!==void 0);case`emit_finding`:return[r(`path`,n.path),r(`line`,n.line)].filter(e=>e!==void 0);default:return[]}}function xa(e,t){let n=va(t),r=(e,t)=>{let n=ga(t);return n?`${e}=${n}`:void 0};switch(e){case`get_file_content`:case`get_related_file_content`:return[r(`lines`,n.returnedEndLine),r(`status`,n.status)].filter(e=>e!==void 0);case`get_file_diff`:case`get_file_diff_hunk`:return[r(`truncated`,n.truncated),r(`patch_chars`,n.returnedPatchChars),r(`total_hunks`,n.totalHunks)].filter(e=>e!==void 0);case`search_text_in_repo`:case`search_symbol_name`:return[r(`matches`,n.totalMatches),r(`filtered`,n.filteredMatchCount),r(`truncated`,n.truncated)].filter(e=>e!==void 0);case`get_file_list_by_directory`:return[r(`files`,n.totalFiles),r(`filtered`,n.filteredFileCount),r(`truncated`,n.truncated)].filter(e=>e!==void 0);case`list_changed_files`:case`get_pr_overview`:{let e=Array.isArray(n.reviewedFiles)?n.reviewedFiles.length:void 0,t=Array.isArray(n.skippedFiles)?n.skippedFiles.length:void 0;return[r(`reviewed_files`,e),r(`skipped_files`,t)].filter(e=>e!==void 0)}case`get_ci_summary`:return[r(`status`,n.status)].filter(e=>e!==void 0);default:return[]}}function Sa(e,t,n){let r=Or(n.reviewedFileCount)?`file_summaries=${n.summaryDrafts.fileSummaries.length}/${n.reviewedFileCount}`:`file_summaries=disabled`;return[`findings=${t.length}/${e.review.maxFindings}`,r,`pr_summary=${n.summaryDrafts.prSummary?`recorded`:`missing`}`]}function Ca(e){if(typeof e==`string`)return e.length;try{return JSON.stringify(e)?.length??0}catch{return 0}}function wa(e){let t=va(e).toolTelemetry;if(t&&typeof t==`object`&&!Array.isArray(t)&&typeof t.durationMs==`number`)return t.durationMs}function Ta(e){let t=va(e);for(let e of[`filteredMatchCount`,`filteredFileCount`,`filteredCount`]){let n=t[e];if(typeof n==`number`&&Number.isFinite(n))return n}return 0}function Ea(e){return va(e).truncated===!0}function Da(e,t){let n=e.toolStartedAtMsByName?.get(t);if(!n||n.length===0)return;let r=n.shift();return n.length===0&&e.toolStartedAtMsByName?.delete(t),r}function Oa(){return{requested:0,allowed:0,denied:0,completed:0,resultCounts:{},totalDurationMs:0,maxDurationMs:0,totalInputChars:0,totalOutputChars:0,truncatedResponses:0,filteredResultCount:0}}function ka(){return{totalRequested:0,totalAllowed:0,totalDenied:0,totalCompleted:0,totalDurationMs:0,sessionDurationMs:0,errorCount:0,assistantMessageChars:0,byTool:{}}}function Aa(e,t){let n=e.byTool[t];if(n)return n;let r=Oa();return e.byTool[t]=r,r}function ja(e){return[`Copilot requested tool`,e.toolName,...ba(e.toolName,e.toolArgs)].join(` `)}function Ma(e,t,n,r){return[`Copilot completed tool`,e.toolName,`result=${e.toolResult.resultType}`,ga(wa(e.toolResult))?`duration_ms=${ga(wa(e.toolResult))}`:void 0,ga(e.toolResult.error)?`error=${ga(e.toolResult.error)}`:void 0,...ba(e.toolName,e.toolArgs),...xa(e.toolName,e.toolResult),...Sa(t,n,r)].filter(e=>e!==void 0).join(` `)}function Na(e,t,n,r={reviewedFileCount:0,summaryDrafts:{fileSummaries:[]},toolTelemetry:ka(),toolStartedAtMsByName:new Map}){return{onSessionStart:async()=>({additionalContext:da(e,r.reviewedFileCount)}),onPreToolUse:async e=>{let n=r.toolTelemetry??ka();if(r.toolTelemetry=n,n.totalRequested+=1,Aa(n,e.toolName).requested+=1,t.info(ja(e)),!ua(e.toolName))return n.totalDenied+=1,Aa(n,e.toolName).denied+=1,{permissionDecision:`deny`,permissionDecisionReason:`Tool ${e.toolName} is not allowed in CI review mode.`};n.totalAllowed+=1;let i=Aa(n,e.toolName);i.allowed+=1,i.totalInputChars+=Ca(e.toolArgs);let a=r.toolStartedAtMsByName??new Map;return r.toolStartedAtMsByName=a,a.set(e.toolName,[...a.get(e.toolName)??[],Date.now()]),{permissionDecision:`allow`,additionalContext:fa(e.toolName,r.reviewedFileCount)}},onPostToolUse:async i=>{let a=r.toolTelemetry??ka();r.toolTelemetry=a,a.totalCompleted+=1;let o=Aa(a,i.toolName);o.completed+=1,o.totalOutputChars+=Ca(i.toolResult);let s=wa(i.toolResult)??(()=>{let e=Da(r,i.toolName);return e===void 0?0:Date.now()-e})();o.totalDurationMs+=s,o.maxDurationMs=Math.max(o.maxDurationMs,s),a.totalDurationMs+=s,Ea(i.toolResult)&&(o.truncatedResponses+=1),o.filteredResultCount+=Ta(i.toolResult);let c=i.toolResult.resultType;return o.resultCounts[c]=(o.resultCounts[c]??0)+1,t.info(Ma(i,e,n,r)),ua(i.toolName)?{additionalContext:pa(i.toolName,n.length,e.review,r.reviewedFileCount)}:{additionalContext:`Keep findings distinct, evidence-backed, and continue until the reviewed risky changes have been covered.`}},onErrorOccurred:async e=>{let n=r.toolTelemetry??ka();return r.toolTelemetry=n,n.errorCount+=1,t.warn(`Copilot session reported an error in ${e.errorContext}`,e.error),{errorHandling:`abort`}}}}function Pa(e,t,n){if(e.reviewedFiles.length===0)return`No reviewable files remained after exclusions, so no AI review was performed.`;if(n===0){let n=t?.trim();return n&&n.length>0?O(n,1200,{suffix:`
|
|
35
|
+
... truncated ...`}):`No ${e.reviewedFiles.length>0?`reportable`:`reviewable`} issues found in the reviewed pull request changes at the configured confidence threshold.`}return`Copilot identified ${n} reportable issue${n===1?``:`s`} in the reviewed pull request changes.`}async function Fa(e,t,n,r,i={}){if(t.reviewedFiles.length===0)return{summary:Pa(t,void 0,0),findings:[],stale:!1};let a=[],o={fileSummaries:[]},s=ka(),c=Date.now(),l=ma(e,i.resolveCliPath),u=i.createCopilotClient?.(l)??new hr(l);await u.start();let d=await(i.createReviewSession?.({client:u,config:e,context:t,git:n,logger:r,drafts:a,summaryDrafts:o})??u.createSession({clientName:`bitbucket-copilot-pr-review`,model:e.copilot.model,reasoningEffort:e.copilot.reasoningEffort,streaming:!0,tools:ca(e,t,n,a,o),availableTools:[...sa],onPermissionRequest:gr,hooks:Na(e,r,a,{reviewedFileCount:t.reviewedFiles.length,summaryDrafts:o,toolTelemetry:s}),workingDirectory:e.repoRoot,infiniteSessions:{enabled:!1}}));la(d,r);try{let n=await d.sendAndWait({prompt:Gr(e,t)},e.copilot.timeoutMs),r=Dr(a,t.reviewedFiles,e.review.maxFindings,e.review.minConfidence),i=Lr(t,o),l=n?.data.content;return s.sessionDurationMs=Date.now()-c,s.assistantMessageChars=l?.length??0,w({summary:Pa(t,l,r.length),findings:r,assistantMessage:l,prSummary:i.prSummary,fileSummaries:i.fileSummaries,toolTelemetry:s,stale:!1})}finally{await d.disconnect();let e=await u.stop();s.errorCount+=e.length;for(let t of e)r.warn(`Copilot client cleanup reported an error`,t)}}async function Ia(e){if(!t.stdin.isTTY||!t.stdout.isTTY)throw Error(`review --confirm-rerun requires an interactive terminal (TTY) so you can answer the prompt.`);let n=re({input:t.stdin,output:t.stdout});try{let t=await n.question(`${e.message}\nRerun review anyway? [y/N] `);return/^(y|yes)$/i.test(t.trim())}finally{n.close()}}function La(e,t){let n=e.replace(/\\/g,`/`);return t.find(e=>g.posix.matchesGlob(n,e))}function Ra(e,t,n){let r=oi(e);if(!r.include)return{include:!1,reason:n?`${n} rejected: ${r.reason}`:r.reason};let i=La(e,t);return i?{include:!1,reason:n?`${n} rejected: ignored path pattern (${i})`:`ignored path pattern (${i})`}:{include:!0}}function za(e,t=[]){if(e.status===`deleted`)return{include:!1,reason:`deleted file`};if(e.isBinary)return{include:!1,reason:`binary diff`};let n=Ra(e.path,t);if(!n.include)return{include:!1,reason:n.reason};if(e.oldPath){let n=Ra(e.oldPath,t,`source path`);if(!n.include)return{include:!1,reason:n.reason}}return e.patch.trim().length===0?{include:!1,reason:`empty textual diff`}:{include:!0}}function Ba(e,t,n=[]){let r=[],i=[];for(let t of e){let e=za(t,n);if(!e.include){i.push(w({path:t.path,oldPath:t.oldPath,status:t.status,reason:e.reason||`excluded by review policy`}));continue}r.push(t)}return r.length<=t?{reviewedFiles:r,skippedFiles:i}:{reviewedFiles:r.slice(0,t),skippedFiles:i.concat(r.slice(t).map(e=>w({path:e.path,oldPath:e.oldPath,status:e.status,reason:`exceeds REVIEW_MAX_FILES limit (${t})`})))}}function Va(){return`2`}function Ha(e){let t=JSON.stringify({schema:`2`,baseCommit:e.baseCommit,mergeBaseCommit:e.mergeBaseCommit,rawDiff:e.rawDiff});return f(`sha256`).update(t).digest(`hex`)}async function Ua(e,t){if(e)try{let t=(await o(e,`utf8`)).trim();return t?O(t,8e3,{suffix:`
|
|
36
|
+
... truncated ...`}):void 0}catch(n){t.warn(`Unable to read CI summary file at ${e}`,n);return}}function Wa(e){let t=new Set([`AGENTS.md`]);for(let n of e){let e=n.split(`/`);for(let n=1;n<e.length;n+=1){let r=e.slice(0,n).join(`/`);r.length>0&&t.add(`${r}/AGENTS.md`)}}return[...t].sort((e,t)=>e.split(`/`).length-t.split(`/`).length||e.localeCompare(t))}async function Ga(e,t,n,r){try{let i=Wa(n);if(i.length===0){r.debug(`No trusted AGENTS.md files found at ${t}`);return}let a=[];for(let r of i){let i=await e.readTextFileAtCommit(t,r);if(i.status!==`ok`)continue;let o=i.content.trim();if(!o)continue;let s=r===`AGENTS.md`?[`.`]:n.filter(e=>{let t=r.slice(0,-10);return e===t||e.startsWith(`${t}/`)});a.push({path:r,appliesTo:s,content:O(o,12e3,{suffix:`
|
|
37
|
+
... truncated ...`})})}return a.length===0?void 0:(r.info(`Loaded ${a.length} trusted AGENTS.md file${a.length===1?``:`s`} from base commit ${t}`),a)}catch(e){r.warn(`Unable to read trusted AGENTS.md instructions from base commit ${t}`,e);return}}async function Ka(e,t,n){let r=new Pt(e.repoRoot,t,e.gitRemoteName);await r.ensurePullRequestCommits(n);let i=await r.mergeBase(n.target.latestCommit,n.source.latestCommit),a=await Wt(e,r,n.target.latestCommit,t),o=await r.diff(i,n.source.latestCommit),s=$i(o),c=Ha({baseCommit:n.target.latestCommit,mergeBaseCommit:i,rawDiff:o}),l=Ba(s.files,a.review.maxFiles,a.review.ignorePaths),u=await Ua(e.ciSummaryPath,t),d=await Ga(r,n.target.latestCommit,l.reviewedFiles.map(e=>e.path),t);return{config:a,git:r,context:w({repoRoot:a.repoRoot,pr:n,headCommit:n.source.latestCommit,baseCommit:n.target.latestCommit,mergeBaseCommit:i,reviewRevision:c,rawDiff:o,diffStats:s.stats,reviewedFiles:l.reviewedFiles,skippedFiles:l.skippedFiles,repoAgentsInstructions:d,ciSummary:u})}}function qa(e,t){return{stage:e,message:t instanceof Error?t.message:String(t)}}async function Ja(e,t,n,r){try{await e.upsertPullRequestComment(t.report.commentTag,n.commentBody,{strategy:t.report.commentStrategy})}catch(i){r.warn(`Pull request comment update failed once; retrying before marking publication partial.`,i),await e.upsertPullRequestComment(t.report.commentTag,n.commentBody,{strategy:t.report.commentStrategy})}}async function Ya(e,t,n,r,i,a){if(t.review.dryRun)return a.info(`Dry run enabled, skipping Bitbucket Code Insights publish.`),{published:!1,publication:{status:`dry_run`,attempted:!1,codeInsightsPublished:!1,pullRequestCommentUpdated:!1},review:r};let o=await e.getPullRequest();if(o.source.latestCommit!==n.headCommit)return a.warn(`Skipping publish because the PR head moved from ${n.headCommit} to ${o.source.latestCommit}`),{published:!1,publication:{status:`stale`,attempted:!1,codeInsightsPublished:!1,pullRequestCommentUpdated:!1},review:{...r,stale:!0}};try{await e.publishCodeInsights(n.headCommit,t.report.key,i.report,i.annotations)}catch(e){let t=qa(`code_insights`,e);return a.error(`Bitbucket publication failed before the PR comment update at stage ${t.stage}: ${t.message}`,e),{published:!1,publication:{status:`failed`,attempted:!0,codeInsightsPublished:!1,pullRequestCommentUpdated:!1,error:t},review:r}}try{await Ja(e,t,i,a)}catch(e){let t=qa(`pull_request_comment`,e);return a.error(`Bitbucket publication completed the report publish but failed during PR comment update: ${t.message}`,e),{published:!1,publication:{status:`partial`,attempted:!0,codeInsightsPublished:!0,pullRequestCommentUpdated:!1,error:t},review:r}}return{published:!0,publication:{status:`published`,attempted:!0,codeInsightsPublished:!0,pullRequestCommentUpdated:!0},review:r}}const Xa=`Review revision`,Za=`Review schema`,Qa=`Reviewed commit`,$a=`findings-json`,eo=[`schema`,`revision`,`reviewed-commit`,`published-commit`,$a];function to(e){return ie(Buffer.from(e,`utf8`)).toString(`base64`)}function no(e){try{return x(Buffer.from(e,`base64`)).toString(`utf8`)}catch{try{return Buffer.from(e,`base64`).toString(`utf8`)}catch{return}}}function ro(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function io(e,t){return e?.data?.find(e=>e.title===t)?.value}function ao(e,t){let n=io(e,t);if(typeof n!=`string`)return;let r=n.trim();return r.length>0?r:void 0}function oo(e,t){return RegExp(`^<!--\\s*${ro(e)}(?::[^>]*)?\\s*-->$`).test(t.trim())}function so(e){return`<!-- ${e} -->`}function co(e){let t=e.schema??Va();return[`<!-- ${e.tag}:schema:${t} -->`,`<!-- ${e.tag}:revision:${e.revision} -->`,`<!-- ${e.tag}:reviewed-commit:${e.reviewedCommit} -->`,`<!-- ${e.tag}:published-commit:${e.publishedCommit} -->`,...e.findingsJson?[`<!-- ${e.tag}:${$a}:${to(e.findingsJson)} -->`]:[]]}function lo(e,t){let n=e.split(/\r?\n/).filter(e=>!oo(t.tag,e)).join(`
|
|
38
|
+
`).trim();return[[so(t.tag),...co(t)].join(`
|
|
39
|
+
`),n].filter(e=>e.length>0).join(`
|
|
40
|
+
|
|
41
|
+
`)}function uo(e,t){if(!t.includes(so(e)))return;let n={};for(let r of eo){let i=RegExp(`<!--\\s*${ro(e)}:${ro(r)}:([^>]+?)\\s*-->`).exec(t)?.[1]?.trim();if(i)switch(r){case`schema`:n.schema=i;break;case`revision`:n.revision=i;break;case`reviewed-commit`:n.reviewedCommit=i;break;case`published-commit`:n.publishedCommit=i;break;case $a:{let e=no(i);if(!e)break;try{let t=JSON.parse(e);Array.isArray(t)&&(n.storedFindings=t.filter(e=>!!(e&&typeof e==`object`&&typeof e.path==`string`&&typeof e.severity==`string`&&typeof e.type==`string`&&typeof e.title==`string`)))}catch{}break}}}return n}function fo(e){let t=io(e,`Findings`);if(typeof t==`number`&&Number.isFinite(t))return t;if(typeof t==`string`&&/^\d+$/.test(t.trim()))return Number.parseInt(t.trim(),10)}function po(e){return ao(e,Xa)}function mo(e){return ao(e,Za)}function ho(e){return ao(e,Qa)}function go(e){return[{title:Xa,type:`TEXT`,value:e.revision},{title:Za,type:`TEXT`,value:e.schema??Va()},{title:Qa,type:`TEXT`,value:e.reviewedCommit}]}const _o=[`added`,`modified`,`renamed`,`copied`,`deleted`],vo=[`BUG`,`VULNERABILITY`,`CODE_SMELL`],yo=[`deleted file`,`binary diff`,`generated or vendored path`,`binary or generated extension`,`ignored path pattern`,`lockfile`,`potential secret-bearing path`,`empty textual diff`];function $(e,t,n=`${t}s`){return e===1?t:n}function bo(e){return encodeURIComponent(e).replace(/%20/g,`+`)}function xo(e,t,n){if(e)return`${e.replace(/\/$/,``)}/diff#${bo(t)}${n&&n>0?`?t=${n}`:``}`}function So(e,t,n=!0){return t?`[${e.replace(/\\/g,`\\\\`).replace(/\[/g,`\\[`).replace(/\]/g,`\\]`)}](${t})`:n?`\`${e}\``:e}function Co(e){let t=[`Type: ${e.type}`,`Severity: ${e.severity}`,`Confidence: ${e.confidence}`];return e.category&&t.push(`Category: ${e.category}`),t.join(` | `)}function wo(e){return`${e.type}/${e.severity}/${e.confidence}`}function To(e){if(e.length===0)return;let t=new Map;for(let n of e)t.set(n.type,(t.get(n.type)??0)+1);let n=vo.flatMap(e=>{let n=t.get(e)??0;if(n===0)return[];switch(e){case`BUG`:return`${n} ${$(n,`bug`)}`;case`VULNERABILITY`:return`${n} ${$(n,`vulnerability`,`vulnerabilities`)}`;case`CODE_SMELL`:return`${n} ${$(n,`code smell`)}`;default:return[]}});return n.length>0?n.join(`, `):void 0}function Eo(e){let t=[e.title,Co(e)];return e.details.length>0&&t.push(e.details),O(t.join(`
|
|
42
|
+
`),1800)}function Do(e){return e.map((e,t)=>{let n=e.line>0?`${e.path}:${e.line}`:e.path;return`${t+1}. [${wo(e)}] ${n} - ${e.title}`})}function Oo(e){if(e.length===0)return;let t=e.map(e=>w({path:e.path,line:e.line>0?e.line:void 0,severity:e.severity,type:e.type,confidence:e.confidence,title:e.title,details:e.details.length>0?e.details:void 0,category:e.category,externalId:e.externalId}));return JSON.stringify(t)}function ko(e,t){return t.map((t,n)=>{let r=So(t.line>0?`${t.path}:${t.line}`:t.path,xo(e,t.path,t.line));return`${n+1}. [${wo(t)}] ${r} - ${t.title}`})}function Ao(e){if(e.length===0)return[];let t=To(e);return t?[`- Main risks: ${t}`]:[]}function jo(e){if(e.length===0)return;let t=new Map;for(let n of e)t.set(n.status,(t.get(n.status)??0)+1);let n=_o.flatMap(e=>{let n=t.get(e)??0;return n===0?[]:`${n} ${$(n,`${e} file`,`${e} files`)}`});return n.length>0?n.join(`, `):void 0}function Mo(e){if(e.length===0)return;let t=new Map;for(let n of e){let e=Nr(n.reason);t.set(e,(t.get(e)??0)+1)}let n=[...yo.filter(e=>t.has(e)),...[...t.keys()].filter(e=>!yo.includes(e)).sort()].map(e=>`${e} (${t.get(e)??0})`);return n.length>0?n.join(`, `):void 0}function No(e){return`${e.reviewedFiles.length} reviewed, ${e.skippedFiles.length} skipped`}function Po(e,t){return[`### What Changed`,t.prSummary??Pr(e)].join(`
|
|
43
|
+
`)}function Fo(e){let t=e.findings.length,n=To(e.findings);return[`### Conclusion`,e.summary,t>0?`- Recommendation: address ${t} reportable ${$(t,`issue`)} before merge.`:`- Recommendation: no reportable issues found in the reviewed scope.`,...t>0&&n?[`- Main risks: ${n}`]:[]].join(`
|
|
44
|
+
`)}function Io(e,t){if(!Or(e.reviewedFiles.length))return[];let n=new Map((t.fileSummaries??[]).map(e=>[e.path,e.summary])),r=e.reviewedFiles.map(t=>`- ${So(t.path,xo(e.pr.link,t.path))}: ${n.get(t.path)??`Reviewed change.`}`);return r.length===0?[`- No changed files captured from the diff.`]:r}function Lo(e){return e.skippedFiles.map(t=>`- ${So(t.path,xo(e.pr.link,t.path))}: ${Ir(t)}`)}function Ro(e){return e.join(`
|
|
45
|
+
|
|
46
|
+
`).trim().length}function zo(e){if(e.lines.length===0)return;let t=t=>{let n=e.lines.length-t,r=[...e.pinnedLines??[],...e.lines.slice(0,t)];n>0&&r.push(`- ... ${n} more ${e.omittedLabel} omitted to fit Bitbucket comment limit.`);let i=[e.heading,...r].join(`
|
|
47
|
+
`);return Ro([...e.baseSections,i])<=e.maxChars?i:void 0};for(let n=e.lines.length;n>=0;--n){let e=t(n);if(e)return e}}function Bo(e){let t=jo([...e.reviewedFiles,...e.skippedFiles]),n=Mo(e.skippedFiles);return[`### Review Scope`,`- PR: ${So(`#${e.pr.id} ${e.pr.title}`,e.pr.link,!1)}`,`- Branches: \`${e.pr.source.displayId}\` -> \`${e.pr.target.displayId}\``,`- Diff size: ${e.diffStats.fileCount} ${$(e.diffStats.fileCount,`file`)}, +${e.diffStats.additions}, -${e.diffStats.deletions}`,...t?[`- Change mix: ${t}`]:[],`- Reviewed in scope: ${e.reviewedFiles.length} ${$(e.reviewedFiles.length,`file`)}`,`- Outside scope: ${e.skippedFiles.length} ${$(e.skippedFiles.length,`file`)}`,...n?[`- Outside-scope reasons: ${n}`]:[]].join(`
|
|
48
|
+
`)}function Vo(e,t,n){let r=To(n.findings);return[{title:`Findings`,type:`NUMBER`,value:n.findings.length},...r?[{title:`Finding taxonomy`,type:`TEXT`,value:r}]:[],...go({revision:t.reviewRevision,reviewedCommit:t.headCommit}),{title:`Review scope`,type:`TEXT`,value:No(t)}]}function Ho(e,t,n){let r=n.findings.length>0?`\n\nTaxonomy: ${To(n.findings)??`reportable findings`}\n\nTop validated findings:\n${Do(n.findings).join(`
|
|
49
|
+
`)}`:``,i=O(`${n.summary}\n\nAdvisory AI review generated by GitHub Copilot. Only validated findings on reviewable changed files and changed lines are published.${r}`,1900),a=n.findings.length>0?`FAIL`:`PASS`;return w({title:e.report.title,details:i,result:a,reporter:e.report.reporter,link:e.report.link,data:Vo(e,t,n)})}function Uo(e,t){return t.map(t=>w({externalId:t.externalId,path:t.path,line:t.line>0?t.line:void 0,message:Eo(t),severity:t.severity,type:t.type,link:e.report.link}))}function Wo(e,t,n){let r=so(e.report.commentTag),i=co({tag:e.report.commentTag,revision:t.reviewRevision,reviewedCommit:t.headCommit,publishedCommit:t.headCommit,...w({findingsJson:Oo(n.findings)})}),a=`## ${e.report.title}`,o=Fo(n),s=Po(t,n),c=Bo(t),l=[r,...i,a,o,s,c].filter(e=>e&&e.trim().length>0).map(e=>e.trim()),u=[];for(let[e,r,i]of[[`### Main Concerns`,ko(t.pr.link,n.findings),$(n.findings.length,`finding`)],[`### Reviewed Changes`,Io(t,n),$(t.reviewedFiles.length,`file summary`,`file summaries`)],[`### Outside Review Scope`,Lo(t),$(t.skippedFiles.length,`skipped file`,`skipped files`)]]){let t=zo({baseSections:[...l,...u],heading:e,...e===`### Main Concerns`?{pinnedLines:Ao(n.findings)}:{},lines:r,omittedLabel:i,maxChars:D});t&&u.push(t)}return O([...l,...u].join(`
|
|
50
|
+
|
|
51
|
+
`).trim(),D,{preserveMaxLength:!0})}function Go(e,t,n,r,i){return{context:{prId:t.id,title:t.title,sourceBranch:t.source.displayId,targetBranch:t.target.displayId,headCommit:t.source.latestCommit,mergeBaseCommit:i??t.target.latestCommit,...r?{reviewRevision:r}:{},reviewedFiles:0,skippedFiles:0},review:{summary:n,findings:[],stale:!1},report:{title:e.report.title,result:`PASS`,reporter:e.report.reporter},annotations:[],published:!1,skipped:!0,skipReason:n}}function Ko(e,t,n){return{report:Ho(e,t,n),annotations:Uo(e,n.findings),commentBody:Wo(e,t,n)}}function qo(e,t,n,r,i){let{gitTelemetry:a,toolTelemetry:o,...s}=t,c=a!==void 0&&Object.keys(a.byOperation).length>0;return{context:{prId:e.pr.id,title:e.pr.title,sourceBranch:e.pr.source.displayId,targetBranch:e.pr.target.displayId,headCommit:e.headCommit,mergeBaseCommit:e.mergeBaseCommit,...e.reviewRevision?{reviewRevision:e.reviewRevision}:{},reviewedFiles:e.reviewedFiles.length,skippedFiles:e.skippedFiles.length},...w({metrics:c||o?{...c&&a?{gitTelemetry:a}:{},...o?{toolTelemetry:o}:{}}:void 0}),review:s,report:n.report,annotations:n.annotations,commentBody:n.commentBody,published:r,...i?{publication:i,publicationStatus:i.status}:{},skipped:!1}}function Jo(e,t){return t.reportCommit===e.headCommit&&t.reportRevision===e.reviewRevision}function Yo(e){let[t=e.message,n=``,...r]=e.message.split(/\r?\n/),i=/Confidence:\s*(low|medium|high)/i.exec(n);return{title:t.trim(),...i?.[1]?{confidence:i[1].toLowerCase()}:{},details:r.join(`
|
|
52
|
+
`).trim()}}function Xo(e){let t=e?.details?.trim();return t&&t.split(/\n\nAdvisory AI review generated/)[0]?.split(/\n\nTop findings:/)[0]?.trim()||`Reused the existing review artifacts for an unchanged PR revision.`}function Zo(e,t,n){return{externalId:e.externalId??`reused-finding-${t+1}`,path:e.path,line:e.line??0,severity:e.severity,type:e.type,confidence:e.confidence??n.review.minConfidence,title:e.title,details:e.details??``,...e.category?{category:e.category}:{}}}function Qo(e,t,n){let r=t.commentStoredFindings;if(r&&r.length>0)return{summary:Xo(t.existingReport),findings:r.map((e,t)=>Zo(e,t,n)),stale:!1,fileSummaries:[]};let i=t.existingAnnotations.map(t=>{let r=Yo(t);return{externalId:t.externalId,path:t.path??e.reviewedFiles[0]?.path??``,line:t.line??0,severity:t.severity,type:t.type??`BUG`,confidence:r.confidence??n.review.minConfidence,title:r.title,details:r.details}});return{summary:Xo(t.existingReport),findings:i,stale:!1,fileSummaries:[]}}function $o(e,t){if(!t.existingReport||!t.reportCommit||t.reportSchema!==Va()||t.reportRevision!==e.reviewRevision||t.reportReviewedCommit!==t.reportCommit)return!1;let n=fo(t.existingReport);return n===void 0?!1:t.existingAnnotations.length===n||(t.commentStoredFindings?.length??0)===n}function es(e,t){let n=[];return t.reportSchema!==Va()&&n.push(`report schema ${t.reportSchema??`missing`} != ${Va()}`),t.reportRevision!==e.reviewRevision&&n.push(`report revision ${t.reportRevision??`missing`} != ${e.reviewRevision}`),t.reportReviewedCommit!==t.reportCommit&&n.push(`report reviewed commit ${t.reportReviewedCommit??`missing`} != stored report commit ${t.reportCommit}`),t.commentRevision!==e.reviewRevision&&n.push(`comment revision ${t.commentRevision??`missing`} != ${e.reviewRevision}`),t.commentReviewedCommit!==e.headCommit&&n.push(`comment reviewed commit ${t.commentReviewedCommit??`missing`} != ${e.headCommit}`),t.commentPublishedCommit!==e.headCommit&&n.push(`comment published commit ${t.commentPublishedCommit??`missing`} != ${e.headCommit}`),t.expectedAnnotationCount===void 0?n.push(`report findings field is missing or invalid`):t.storedAnnotationCount!==t.expectedAnnotationCount&&n.push(`stored annotation count ${t.storedAnnotationCount} != findings ${t.expectedAnnotationCount}`),t.expectedAnnotationCount!==void 0&&Math.max(t.reusableAnnotationCount,t.storedFindingCount)!==t.expectedAnnotationCount&&n.push(`reusable finding count ${Math.max(t.reusableAnnotationCount,t.storedFindingCount)} != findings ${t.expectedAnnotationCount}`),n}async function ts(e,t,n){let r=await e.findPullRequestCommentByTag(t.report.commentTag),i=r?uo(t.report.commentTag,r.text):void 0,a=i?.reviewedCommit??n.headCommit,o=n.headCommit,s=await e.getCodeInsightsReport(n.headCommit,t.report.key),c=s?await e.getCodeInsightsAnnotationCount(n.headCommit,t.report.key):0,l=s?await e.listCodeInsightsAnnotations(n.headCommit,t.report.key):[];!s&&a!==n.headCommit&&(s=await e.getCodeInsightsReport(a,t.report.key),c=s?await e.getCodeInsightsAnnotationCount(a,t.report.key):0,l=s?await e.listCodeInsightsAnnotations(a,t.report.key):[],o=a);let u=po(s),d=ho(s),f=mo(s),p=fo(s),m=o===n.headCommit&&f===Va()&&u===n.reviewRevision&&d===n.headCommit&&i?.revision===n.reviewRevision&&i.reviewedCommit===n.headCommit&&i.publishedCommit===n.headCommit&&p===c&&(i?.storedFindings===void 0||i.storedFindings.length===p),h=s?es(n,{reportCommit:o,storedFindingCount:i?.storedFindings?.length??0,storedAnnotationCount:c,reusableAnnotationCount:l.length,...f?{reportSchema:f}:{},...u?{reportRevision:u}:{},...d?{reportReviewedCommit:d}:{},...i?.revision?{commentRevision:i.revision}:{},...i?.reviewedCommit?{commentReviewedCommit:i.reviewedCommit}:{},...i?.publishedCommit?{commentPublishedCommit:i.publishedCommit}:{},...p===void 0?{}:{expectedAnnotationCount:p}}):[];return{existingReport:s,storedAnnotationCount:c,existingAnnotations:l,existingComment:r,existingPublicationComplete:m,...s?{reportCommit:o}:{},...u?{reportRevision:u}:{},...d?{reportReviewedCommit:d}:{},...f?{reportSchema:f}:{},...i?.revision?{commentRevision:i.revision}:{},...i?.publishedCommit?{commentPublishedCommit:i.publishedCommit}:{},...i?.reviewedCommit?{commentReviewedCommit:i.reviewedCommit}:{},...i?.storedFindings?{commentStoredFindings:i.storedFindings}:{},unusableReasons:h}}function ns(e,t,n){if(e.review.forceReview)return{action:`review`};if(n.existingPublicationComplete)return{action:`skip`,reason:`Skipping review because PR revision ${t.reviewRevision} already has a fully published report ${e.report.key} for head ${t.headCommit}. Use --force-review or REVIEW_FORCE=1 to override.`};if($o(t,n)){let r=Qo(t,n,e),i=n.existingAnnotations.length>0?n.existingAnnotations:Uo(e,r.findings),a=n.existingComment?lo(n.existingComment.text,{tag:e.report.commentTag,revision:t.reviewRevision,reviewedCommit:n.reportReviewedCommit??n.reportCommit??t.headCommit,publishedCommit:t.headCommit,...n.commentStoredFindings?{findingsJson:JSON.stringify(n.commentStoredFindings)}:{}}):Wo(e,t,r);return{action:`republish`,repairWarning:n.reportCommit===t.headCommit?`Repairing the published artifacts for unchanged PR revision ${t.reviewRevision} on head ${t.headCommit} without rerunning review.`:`Reusing the existing review for unchanged PR revision ${t.reviewRevision} from head ${n.reportCommit} and republishing it onto head ${t.headCommit}.`,reusedReview:r,reusedArtifacts:{report:n.existingReport,annotations:i,commentBody:a}}}if(n.existingReport){let r=n.unusableReasons.length>0?` Details: ${n.unusableReasons.join(`; `)}.`:``,i=Jo(t,n)?`Existing cached artifacts for PR revision ${t.reviewRevision} look unusable. ${n.unusableReasons.join(`; `)||`No additional details available.`}`:void 0;return{action:`review`,repairWarning:`Found an existing but unusable report ${e.report.key} for revision ${t.reviewRevision}; rerunning review to refresh the published output.${r}`,...i?{confirmMessage:i}:{}}}return{action:`review`}}async function rs(e,t,n={}){let r=n.createBitbucketClient?.(e.bitbucket,t)??new be(e.bitbucket,t),i=n.buildReviewContext??Ka,a=n.runCopilotReview??Fa,o=n.confirmRerun??Ia,s=await r.getPullRequest();t.info(`Loaded pull request #${s.id} (${s.source.displayId} -> ${s.target.displayId})`);let c=It(s,e.review.skipBranchPrefixes);if(c)return t.info(c),Go(e,s,c);if(s.state&&s.state!==`OPEN`){let n=`Skipping review because pull request #${s.id} is ${s.state}.`;return t.info(n),Go(e,s,n)}let{config:l,context:u,git:d}=await i(e,t,s),f=It(s,l.review.skipBranchPrefixes);if(f)return t.info(f),Go(l,s,f,u.reviewRevision,u.mergeBaseCommit);t.info(`Review scope after file filtering: ${u.reviewedFiles.length} reviewed, ${u.skippedFiles.length} skipped out of ${u.diffStats.fileCount} changed files (REVIEW_MAX_FILES=${l.review.maxFiles}).`);let p=ns(l,u,await ts(r,l,u));if(p.action===`skip`&&p.reason)return t.info(p.reason),Go(l,s,p.reason,u.reviewRevision,u.mergeBaseCommit);if(e.review.confirmRerun&&p.action===`review`&&p.confirmMessage&&(p.repairWarning&&t.warn(p.repairWarning),!await o({message:p.confirmMessage}))){let e=`Skipped rerun for unchanged PR revision ${u.reviewRevision} after manual confirmation declined.`;return t.info(e),Go(l,s,e,u.reviewRevision,u.mergeBaseCommit)}p.repairWarning&&!(e.review.confirmRerun&&p.action===`review`&&p.confirmMessage)&&t.warn(p.repairWarning);let m=p.action===`republish`&&p.reusedReview?p.reusedReview:await a(l,u,d,t),h=p.action===`republish`&&p.reusedArtifacts?p.reusedArtifacts:Ko(l,u,m),g=await Ya(r,l,u,m,h,t);return qo(u,{...g.review,gitTelemetry:d.getTelemetrySnapshot()},h,g.published,g.publication)}function is(){return process.stderr.isTTY&&process.env.CI!==`true`}function as(e){let t={level:e,base:null,timestamp:ae.stdTimeFunctions.isoTime,formatters:{level(e){return{level:e}}}};return is()?ae(t,ae.transport({target:`pino-pretty`,options:{destination:2,sync:!0,colorize:!0,ignore:`pid,hostname`,translateTime:`SYS:standard`}})):ae(t,ae.destination({dest:2,sync:!0}))}function os(e){if(e.length===0)return{};if(e.length===1){let[t]=e;return typeof t==`string`?{messageSuffix:t}:{context:t}}return{context:{details:e}}}function ss(e){let t=as(e),n=t.child({stream:`copilot_reasoning`}),r=(e,n,r)=>{let{context:i,messageSuffix:a}=os(r),o=a?`${n} ${a}`:n;if(i===void 0){t[e](o);return}t[e](i,o)};return{debug(e,...t){r(`debug`,e,t)},info(e,...t){r(`info`,e,t)},warn(e,...t){r(`warn`,e,t)},error(e,...t){r(`error`,e,t)},trace(e,...t){let{context:r,messageSuffix:i}=os(t),a=i?`${e} ${i}`:e;if(r===void 0){n.info(a);return}n.info(r,a)},json(e){process.stdout.write(e)}}}function cs(){return t.env.LOG_LEVEL===`debug`}function ls(e){return Se(e)||e instanceof T}function us(e){return e instanceof Error?cs()||!ls(e)?e.stack??e.message:`Error: ${e.message}`:String(e)}async function ds(){let e=t.argv.slice(2),n=Dn(e);if(!(`command`in n)&&n.help){console.log(An(n.commandName));return}if(kn(n)){let r=Wn(e,t.env,n),i=ss(r.logLevel),a=await _n(r,i);a.failed>0&&(t.exitCode=1),i.json(`${JSON.stringify(a,null,2)}\n`);return}if(!On(n))throw Error(`Unable to resolve CLI command.`);let r=Un(e,t.env,n),i=ss(r.logLevel),a=await rs(r,i);delete r.internal,i.json(`${JSON.stringify(a,null,2)}\n`),(a.publicationStatus===`partial`||a.publicationStatus===`failed`)&&(t.exitCode=1)}ds().catch(e=>{t.stderr.write(`${us(e)}\n`),t.exitCode=1});export{};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bitbucket-copilot-pr-review",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Jenkins-driven Bitbucket Data Center pull request review with GitHub Copilot SDK",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/guitaoliu/bitbucket-copilot-pr-review.git"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"bin": {
|
|
11
|
+
"bitbucket-copilot-pr-review": "./dist/cli.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"schemas",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=24.12.0",
|
|
20
|
+
"pnpm": ">=10.29.2"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@github/copilot": "^1.0.7",
|
|
24
|
+
"pino": "^10.3.1",
|
|
25
|
+
"pino-pretty": "^13.1.3",
|
|
26
|
+
"zod": "^4.3.6"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@biomejs/biome": "2.4.7",
|
|
30
|
+
"@github/copilot-sdk": "^0.1.32",
|
|
31
|
+
"@types/node": "^24.12.0",
|
|
32
|
+
"tsdown": "^0.21.4",
|
|
33
|
+
"typescript": "^5.9.3"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsdown",
|
|
37
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
38
|
+
"check": "biome check",
|
|
39
|
+
"check:fix": "biome check --fix",
|
|
40
|
+
"generate:config-docs": "node scripts/generate-config-docs.mjs",
|
|
41
|
+
"release:check": "node scripts/release-check.mjs",
|
|
42
|
+
"verify": "pnpm release:check",
|
|
43
|
+
"review": "pnpm build && node dist/cli.js review",
|
|
44
|
+
"review:dry-run": "pnpm build && node dist/cli.js review --dry-run",
|
|
45
|
+
"review:src": "node src/cli.ts review",
|
|
46
|
+
"review:src:dry-run": "node src/cli.ts review --dry-run",
|
|
47
|
+
"generate:repo-config-schema": "node scripts/generate-repo-config-schema.mjs",
|
|
48
|
+
"test": "node --test \"src/**/*.test.ts\""
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://raw.githubusercontent.com/guitaoliu/bitbucket-copilot-pr-review/main/schemas/copilot-code-review.schema.json",
|
|
3
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"$schema": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"maxLength": 2048,
|
|
9
|
+
"description": "Optional JSON Schema reference for editor support."
|
|
10
|
+
},
|
|
11
|
+
"copilot": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"properties": {
|
|
14
|
+
"model": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"minLength": 1,
|
|
17
|
+
"maxLength": 120,
|
|
18
|
+
"description": "Optional Copilot model override for this repository."
|
|
19
|
+
},
|
|
20
|
+
"reasoningEffort": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"enum": ["low", "medium", "high", "xhigh"],
|
|
23
|
+
"description": "Optional reasoning effort override for this repository."
|
|
24
|
+
},
|
|
25
|
+
"timeoutMs": {
|
|
26
|
+
"type": "integer",
|
|
27
|
+
"minimum": 60000,
|
|
28
|
+
"maximum": 3600000,
|
|
29
|
+
"description": "Optional Copilot timeout in milliseconds."
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"additionalProperties": false
|
|
33
|
+
},
|
|
34
|
+
"report": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"properties": {
|
|
37
|
+
"title": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"minLength": 1,
|
|
40
|
+
"maxLength": 120,
|
|
41
|
+
"description": "Optional Code Insights report title override."
|
|
42
|
+
},
|
|
43
|
+
"commentStrategy": {
|
|
44
|
+
"type": "string",
|
|
45
|
+
"enum": ["update", "recreate"],
|
|
46
|
+
"description": "How the tagged pull request summary comment should be updated."
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"additionalProperties": false
|
|
50
|
+
},
|
|
51
|
+
"review": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"properties": {
|
|
54
|
+
"maxFiles": {
|
|
55
|
+
"type": "integer",
|
|
56
|
+
"minimum": 1,
|
|
57
|
+
"maximum": 500,
|
|
58
|
+
"description": "Maximum number of changed files to review after filtering."
|
|
59
|
+
},
|
|
60
|
+
"maxFindings": {
|
|
61
|
+
"type": "integer",
|
|
62
|
+
"minimum": 1,
|
|
63
|
+
"maximum": 100,
|
|
64
|
+
"description": "Maximum number of findings to publish."
|
|
65
|
+
},
|
|
66
|
+
"minConfidence": {
|
|
67
|
+
"type": "string",
|
|
68
|
+
"enum": ["low", "medium", "high"],
|
|
69
|
+
"description": "Minimum confidence threshold for reportable findings."
|
|
70
|
+
},
|
|
71
|
+
"maxPatchChars": {
|
|
72
|
+
"type": "integer",
|
|
73
|
+
"minimum": 500,
|
|
74
|
+
"maximum": 50000,
|
|
75
|
+
"description": "Maximum diff characters to send for a reviewed file."
|
|
76
|
+
},
|
|
77
|
+
"defaultFileSliceLines": {
|
|
78
|
+
"type": "integer",
|
|
79
|
+
"minimum": 1,
|
|
80
|
+
"maximum": 500,
|
|
81
|
+
"description": "Default line window when reading file content slices."
|
|
82
|
+
},
|
|
83
|
+
"maxFileSliceLines": {
|
|
84
|
+
"type": "integer",
|
|
85
|
+
"minimum": 1,
|
|
86
|
+
"maximum": 1000,
|
|
87
|
+
"description": "Maximum line window allowed for file content slices."
|
|
88
|
+
},
|
|
89
|
+
"ignorePaths": {
|
|
90
|
+
"minItems": 1,
|
|
91
|
+
"maxItems": 200,
|
|
92
|
+
"type": "array",
|
|
93
|
+
"items": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"minLength": 1,
|
|
96
|
+
"maxLength": 512
|
|
97
|
+
},
|
|
98
|
+
"description": "Repo-relative glob patterns for changed files that should be skipped during review."
|
|
99
|
+
},
|
|
100
|
+
"skipBranchPrefixes": {
|
|
101
|
+
"minItems": 1,
|
|
102
|
+
"maxItems": 50,
|
|
103
|
+
"type": "array",
|
|
104
|
+
"items": {
|
|
105
|
+
"type": "string",
|
|
106
|
+
"minLength": 1,
|
|
107
|
+
"maxLength": 128
|
|
108
|
+
},
|
|
109
|
+
"description": "Source branch prefixes that should always be skipped during review."
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"additionalProperties": false
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"additionalProperties": false,
|
|
116
|
+
"title": "Copilot Code Review Config",
|
|
117
|
+
"description": "Trusted repository-level review configuration loaded from copilot-code-review.json at the pull request base commit."
|
|
118
|
+
}
|