@gitkraken/core-gitlens 0.7.2 → 0.9.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.
Files changed (192) hide show
  1. package/CHANGELOG.md +72 -1
  2. package/dist/git/cache.d.ts +29 -5
  3. package/dist/git/cache.js +52 -11
  4. package/dist/git/cache.js.map +1 -1
  5. package/dist/git/context.d.ts +6 -1
  6. package/dist/git/context.js.map +1 -1
  7. package/dist/git/errors.d.ts +28 -1
  8. package/dist/git/errors.js +45 -1
  9. package/dist/git/errors.js.map +1 -1
  10. package/dist/git/features.d.ts +1 -1
  11. package/dist/git/features.js +1 -0
  12. package/dist/git/features.js.map +1 -1
  13. package/dist/git/models/reflog.d.ts +6 -0
  14. package/dist/git/models/reflog.js.map +1 -1
  15. package/dist/git/models/revision.d.ts +0 -1
  16. package/dist/git/models/revision.js +1 -2
  17. package/dist/git/models/revision.js.map +1 -1
  18. package/dist/git/providers/branches.d.ts +5 -1
  19. package/dist/git/providers/commits.d.ts +44 -2
  20. package/dist/git/providers/config.d.ts +7 -1
  21. package/dist/git/providers/operations.d.ts +19 -0
  22. package/dist/git/providers/provider.d.ts +29 -2
  23. package/dist/git/providers/refs.d.ts +48 -3
  24. package/dist/git/providers/revision.d.ts +7 -1
  25. package/dist/git/providers/staging.d.ts +13 -0
  26. package/dist/git/providers/stash.d.ts +3 -2
  27. package/dist/git/providers/status.d.ts +4 -0
  28. package/dist/git/providers/worktrees.d.ts +23 -3
  29. package/dist/git/run.types.d.ts +22 -0
  30. package/dist/git-cli/cliGitProvider.d.ts +39 -2
  31. package/dist/git-cli/cliGitProvider.js +109 -11
  32. package/dist/git-cli/cliGitProvider.js.map +1 -1
  33. package/dist/git-cli/exec/commandClassifier.d.ts +31 -0
  34. package/dist/git-cli/exec/commandClassifier.js +391 -0
  35. package/dist/git-cli/exec/commandClassifier.js.map +1 -0
  36. package/dist/git-cli/exec/git.d.ts +36 -5
  37. package/dist/git-cli/exec/git.js +163 -28
  38. package/dist/git-cli/exec/git.js.map +1 -1
  39. package/dist/git-cli/exec/gitQueue.d.ts +4 -1
  40. package/dist/git-cli/exec/gitQueue.js +1 -1
  41. package/dist/git-cli/exec/gitQueue.js.map +1 -1
  42. package/dist/git-cli/parsers/reflogParser.d.ts +7 -0
  43. package/dist/git-cli/parsers/reflogParser.js +11 -1
  44. package/dist/git-cli/parsers/reflogParser.js.map +1 -1
  45. package/dist/git-cli/providers/branches.d.ts +10 -1
  46. package/dist/git-cli/providers/branches.js +31 -22
  47. package/dist/git-cli/providers/branches.js.map +1 -1
  48. package/dist/git-cli/providers/commits.d.ts +27 -3
  49. package/dist/git-cli/providers/commits.js +112 -12
  50. package/dist/git-cli/providers/commits.js.map +1 -1
  51. package/dist/git-cli/providers/config.js +2 -1
  52. package/dist/git-cli/providers/config.js.map +1 -1
  53. package/dist/git-cli/providers/diff.js +4 -4
  54. package/dist/git-cli/providers/diff.js.map +1 -1
  55. package/dist/git-cli/providers/operations.d.ts +13 -0
  56. package/dist/git-cli/providers/operations.js +64 -5
  57. package/dist/git-cli/providers/operations.js.map +1 -1
  58. package/dist/git-cli/providers/patch.js +21 -45
  59. package/dist/git-cli/providers/patch.js.map +1 -1
  60. package/dist/git-cli/providers/refs.d.ts +20 -3
  61. package/dist/git-cli/providers/refs.js +140 -10
  62. package/dist/git-cli/providers/refs.js.map +1 -1
  63. package/dist/git-cli/providers/remotes.js +3 -2
  64. package/dist/git-cli/providers/remotes.js.map +1 -1
  65. package/dist/git-cli/providers/revision.d.ts +5 -1
  66. package/dist/git-cli/providers/revision.js +20 -5
  67. package/dist/git-cli/providers/revision.js.map +1 -1
  68. package/dist/git-cli/providers/staging.d.ts +9 -0
  69. package/dist/git-cli/providers/staging.js +63 -6
  70. package/dist/git-cli/providers/staging.js.map +1 -1
  71. package/dist/git-cli/providers/stash.d.ts +3 -2
  72. package/dist/git-cli/providers/stash.js +34 -22
  73. package/dist/git-cli/providers/stash.js.map +1 -1
  74. package/dist/git-cli/providers/status.d.ts +2 -0
  75. package/dist/git-cli/providers/status.js +27 -9
  76. package/dist/git-cli/providers/status.js.map +1 -1
  77. package/dist/git-cli/providers/worktrees.d.ts +31 -2
  78. package/dist/git-cli/providers/worktrees.js +75 -7
  79. package/dist/git-cli/providers/worktrees.js.map +1 -1
  80. package/dist/plus/git-github/api/github.d.ts +64 -3
  81. package/dist/plus/git-github/api/github.js +237 -24
  82. package/dist/plus/git-github/api/github.js.map +1 -1
  83. package/dist/plus/git-github/providers/github/branches.d.ts +3 -1
  84. package/dist/plus/git-github/providers/github/branches.js +2 -1
  85. package/dist/plus/git-github/providers/github/branches.js.map +1 -1
  86. package/dist/plus/git-github/providers/github/commits.d.ts +4 -2
  87. package/dist/plus/git-github/providers/github/commits.js +3 -1
  88. package/dist/plus/git-github/providers/github/commits.js.map +1 -1
  89. package/dist/plus/git-github/providers/github/refs.d.ts +10 -3
  90. package/dist/plus/git-github/providers/github/refs.js +4 -4
  91. package/dist/plus/git-github/providers/github/refs.js.map +1 -1
  92. package/dist/plus/git-github/providers/github/revision.d.ts +4 -1
  93. package/dist/plus/git-github/providers/github/revision.js +6 -1
  94. package/dist/plus/git-github/providers/github/revision.js.map +1 -1
  95. package/dist/plus/integrations/index.d.ts +5 -2
  96. package/dist/plus/integrations/index.js.map +1 -1
  97. package/dist/plus/integrations/integrationService.d.ts +35 -9
  98. package/dist/plus/integrations/integrationService.js +16 -3
  99. package/dist/plus/integrations/integrationService.js.map +1 -1
  100. package/dist/plus/integrations/manager.d.ts +107 -37
  101. package/dist/plus/integrations/models/gitHostIntegration.d.ts +128 -13
  102. package/dist/plus/integrations/models/gitHostIntegration.js +130 -17
  103. package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
  104. package/dist/plus/integrations/models/integration.d.ts +51 -3
  105. package/dist/plus/integrations/models/integration.js +125 -18
  106. package/dist/plus/integrations/models/integration.js.map +1 -1
  107. package/dist/plus/integrations/models/issuesIntegration.d.ts +18 -5
  108. package/dist/plus/integrations/models/issuesIntegration.js +40 -10
  109. package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
  110. package/dist/plus/integrations/providers/azure/azure.d.ts +1 -1
  111. package/dist/plus/integrations/providers/azure/azure.js +13 -17
  112. package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
  113. package/dist/plus/integrations/providers/azure/models.d.ts +29 -0
  114. package/dist/plus/integrations/providers/azure/models.js +112 -1
  115. package/dist/plus/integrations/providers/azure/models.js.map +1 -1
  116. package/dist/plus/integrations/providers/azureDevOps.d.ts +54 -2
  117. package/dist/plus/integrations/providers/azureDevOps.js +80 -2
  118. package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
  119. package/dist/plus/integrations/providers/azureDevOpsServer.js +2 -1
  120. package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
  121. package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +61 -0
  122. package/dist/plus/integrations/providers/bitbucket/bitbucket.js +165 -23
  123. package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
  124. package/dist/plus/integrations/providers/bitbucket/models.d.ts +6 -1
  125. package/dist/plus/integrations/providers/bitbucket/models.js +4 -3
  126. package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
  127. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +1 -1
  128. package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
  129. package/dist/plus/integrations/providers/bitbucket-server.d.ts +38 -1
  130. package/dist/plus/integrations/providers/bitbucket-server.js +33 -1
  131. package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
  132. package/dist/plus/integrations/providers/bitbucket.d.ts +36 -1
  133. package/dist/plus/integrations/providers/bitbucket.js +29 -1
  134. package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
  135. package/dist/plus/integrations/providers/github.d.ts +48 -4
  136. package/dist/plus/integrations/providers/github.js +101 -6
  137. package/dist/plus/integrations/providers/github.js.map +1 -1
  138. package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +35 -0
  139. package/dist/plus/integrations/providers/gitlab/gitlab.js +132 -15
  140. package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
  141. package/dist/plus/integrations/providers/gitlab/models.d.ts +1 -0
  142. package/dist/plus/integrations/providers/gitlab/models.js +1 -1
  143. package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
  144. package/dist/plus/integrations/providers/gitlab.d.ts +48 -1
  145. package/dist/plus/integrations/providers/gitlab.js +79 -3
  146. package/dist/plus/integrations/providers/gitlab.js.map +1 -1
  147. package/dist/plus/integrations/providers/jira-server.d.ts +3 -3
  148. package/dist/plus/integrations/providers/jira-server.js +3 -3
  149. package/dist/plus/integrations/providers/jira-server.js.map +1 -1
  150. package/dist/plus/integrations/providers/models.d.ts +12 -1
  151. package/dist/plus/integrations/providers/models.js +11 -1
  152. package/dist/plus/integrations/providers/models.js.map +1 -1
  153. package/dist/plus/integrations/providers/providerErrors.d.ts +9 -1
  154. package/dist/plus/integrations/providers/providerErrors.js +10 -1
  155. package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
  156. package/dist/plus/integrations/providers/providersApi.d.ts +59 -0
  157. package/dist/plus/integrations/providers/providersApi.js +136 -1
  158. package/dist/plus/integrations/providers/providersApi.js.map +1 -1
  159. package/dist/plus/integrations/providers/utils/providerPaging.d.ts +42 -0
  160. package/dist/plus/integrations/providers/utils/providerPaging.js +58 -1
  161. package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
  162. package/dist/plus/integrations/providers/utils.d.ts +1 -1
  163. package/dist/plus/integrations/reads/currentAccount.d.ts +35 -0
  164. package/dist/plus/integrations/reads/currentAccount.js +46 -0
  165. package/dist/plus/integrations/reads/currentAccount.js.map +1 -0
  166. package/dist/plus/integrations/reads/drains.d.ts +4 -1
  167. package/dist/plus/integrations/reads/drains.js +7 -3
  168. package/dist/plus/integrations/reads/drains.js.map +1 -1
  169. package/dist/plus/integrations/reads/issueBatch.d.ts +72 -12
  170. package/dist/plus/integrations/reads/issueBatch.js +193 -48
  171. package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
  172. package/dist/plus/integrations/reads/pullRequestBatch.d.ts +57 -0
  173. package/dist/plus/integrations/reads/pullRequestBatch.js +80 -0
  174. package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -0
  175. package/dist/plus/integrations/reads/pullRequestBranches.d.ts +58 -0
  176. package/dist/plus/integrations/reads/pullRequestBranches.js +111 -0
  177. package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -0
  178. package/dist/plus/integrations/reads/pullRequests.js +3 -3
  179. package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
  180. package/dist/plus/integrations/reads/sweeps.js +3 -3
  181. package/dist/plus/integrations/reads/sweeps.js.map +1 -1
  182. package/dist/plus/integrations/results.d.ts +5 -2
  183. package/dist/plus/integrations/results.js.map +1 -1
  184. package/dist/utils/env/node/exec.js +1 -1
  185. package/dist/utils/env/node/exec.js.map +1 -1
  186. package/docs/integrations.md +90 -36
  187. package/docs/kepler-git-write-api-parity.md +365 -0
  188. package/docs/kepler-read-api-parity.md +75 -28
  189. package/package.json +1 -1
  190. package/dist/plus/integrations/reads/trackerIssue.d.ts +0 -33
  191. package/dist/plus/integrations/reads/trackerIssue.js +0 -60
  192. package/dist/plus/integrations/reads/trackerIssue.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"exec.js","names":["joinPaths"],"sources":["../../../../../utils/src/env/node/exec.ts"],"sourcesContent":["import type { ExecFileException, ExecFileOptions } from 'child_process';\nimport { exec, execFile, spawn } from 'child_process';\nimport type { Stats } from 'fs';\nimport { access, constants } from 'fs';\nimport { stat } from 'fs/promises';\nimport { join as joinPaths } from 'path';\nimport * as process from 'process';\nimport { getScopedLogger, maybeStartScopedLogger } from '../../logger.scoped.js';\nimport { normalizePath } from '../../path.js';\nimport { isWindows } from './platform.js';\n\n// -- Error types --\n\ninterface RunErrorContext {\n\tmessage: string;\n\tcmd?: string | undefined;\n\tkilled?: boolean | undefined;\n\tcode?: string | number | null | undefined;\n\tsignal?: NodeJS.Signals | undefined;\n}\n\nexport class RunError extends Error {\n\treadonly cmd?: string | undefined;\n\treadonly killed?: boolean | undefined;\n\treadonly code?: string | number | undefined;\n\treadonly signal?: NodeJS.Signals | undefined;\n\treadonly stdout: string;\n\treadonly stderr: string;\n\n\tconstructor(context: RunErrorContext, stdout: string, stderr: string) {\n\t\tsuper(context.message);\n\n\t\tthis.cmd = context.cmd;\n\t\tthis.killed = context.killed;\n\t\tthis.code = context.code ?? undefined;\n\t\tthis.signal = context.signal;\n\t\tthis.stdout = stdout?.trim() ?? '';\n\t\tthis.stderr = stderr?.trim() ?? '';\n\n\t\tthis.name = 'RunError';\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\nexport class CancelledRunError extends RunError {\n\tconstructor(cmd: string, killed: boolean, code?: number | string | undefined, signal: NodeJS.Signals = 'SIGTERM') {\n\t\tsuper(\n\t\t\t{ message: `Operation cancelled; command=${cmd}`, cmd: cmd, killed: killed, code: code, signal: signal },\n\t\t\t'',\n\t\t\t'',\n\t\t);\n\n\t\tthis.name = 'CancelledRunError';\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\n// -- Execution utilities --\n\nconst slashesRegex = /[\\\\/]/;\nconst ps1Regex = /\\.ps1$/i;\nconst batOrCmdRegex = /\\.(bat|cmd)$/i;\nconst jsRegex = /\\.(js)$/i;\n\n/**\n * Search PATH to see if a file exists in any of the path folders.\n *\n * @param {string} exe The file to search for\n * @return {string} A fully qualified path, or the original path if nothing\n * is found\n *\n * @private\n */\nasync function runDownPath(exe: string): Promise<string> {\n\t// NB: Windows won't search PATH looking for executables in spawn like\n\t// Posix does\n\n\t// Files with any directory path don't get this applied\n\tif (slashesRegex.test(exe)) return exe;\n\n\tconst target = joinPaths('.', exe);\n\ttry {\n\t\tconst stats = await stat(target);\n\t\tif (stats?.isFile() && isExecutable(stats)) return target;\n\t} catch {}\n\n\tconst path = process.env.PATH;\n\tif (path != null && path.length !== 0) {\n\t\tconst haystack = path.split(isWindows ? ';' : ':');\n\t\tfor (const p of haystack) {\n\t\t\tconst needle = joinPaths(p, exe);\n\t\t\ttry {\n\t\t\t\tconst stats = await stat(needle);\n\t\t\t\tif (stats?.isFile() && isExecutable(stats)) return needle;\n\t\t\t} catch {}\n\t\t}\n\t}\n\n\treturn exe;\n}\n\nfunction isExecutable(stats: Stats) {\n\tif (isWindows) return true;\n\n\tconst isGroup = stats.gid ? stats.gid === process.getgid?.() : true;\n\tconst isUser = stats.uid ? stats.uid === process.getuid?.() : true;\n\n\treturn Boolean(stats.mode & 0o0001 || (stats.mode & 0o0010 && isGroup) || (stats.mode & 0o0100 && isUser));\n}\n\n/**\n * Finds the executable and parameters to run on Windows. This method\n * mimics the POSIX behavior of being able to run scripts as executables by\n * replacing the passed-in executable with the script runner, for PowerShell,\n * CMD, and node scripts.\n *\n * This method also does the work of running down PATH, which spawn on Windows\n * also doesn't do, unlike on POSIX.\n */\nexport async function findExecutable(exe: string, args: string[]): Promise<{ cmd: string; args: string[] }> {\n\t// POSIX can just execute scripts directly, no need for silly goosery\n\tif (!isWindows) return { cmd: await runDownPath(exe), args: args };\n\n\tif (!(await fsExists(exe))) {\n\t\t// NB: When you write something like `surf-client ... -- surf-build` on Windows,\n\t\t// a shell would normally convert that to surf-build.cmd, but since it's passed\n\t\t// in as an argument, it doesn't happen\n\t\tconst possibleExts = ['.exe', '.bat', '.cmd', '.ps1'];\n\t\tfor (const ext of possibleExts) {\n\t\t\tconst possibleFullPath = await runDownPath(`${exe}${ext}`);\n\n\t\t\tif (await fsExists(possibleFullPath)) return findExecutable(possibleFullPath, args);\n\t\t}\n\t}\n\n\tif (ps1Regex.test(exe)) {\n\t\tconst cmd = joinPaths(\n\t\t\tprocess.env.SYSTEMROOT ?? 'C:\\\\WINDOWS',\n\t\t\t'System32',\n\t\t\t'WindowsPowerShell',\n\t\t\t'v1.0',\n\t\t\t'PowerShell.exe',\n\t\t);\n\t\tconst psargs = ['-ExecutionPolicy', 'Unrestricted', '-NoLogo', '-NonInteractive', '-File', exe];\n\n\t\treturn { cmd: cmd, args: [...psargs, ...args] };\n\t}\n\n\tif (batOrCmdRegex.test(exe)) {\n\t\tconst cmd = joinPaths(process.env.SYSTEMROOT ?? 'C:\\\\WINDOWS', 'System32', 'cmd.exe');\n\t\tconst cmdArgs = ['/C', exe, ...args];\n\n\t\treturn { cmd: cmd, args: cmdArgs };\n\t}\n\n\tif (jsRegex.test(exe)) {\n\t\tconst cmd = process.execPath;\n\t\tconst nodeArgs = [exe];\n\n\t\treturn { cmd: cmd, args: [...nodeArgs, ...args] };\n\t}\n\n\treturn { cmd: exe, args: args };\n}\n\nexport async function getWindowsShortPath(path: string): Promise<string> {\n\treturn new Promise<string>((resolve, reject) => {\n\t\texec(`for %I in (\"${path}\") do @echo %~sI`, (error, stdout, _stderr) => {\n\t\t\tif (error != null) {\n\t\t\t\treject(error);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tresolve(normalizePath(stdout.trim()));\n\t\t});\n\t});\n}\n\nexport interface RunOptions<TEncoding = BufferEncoding | 'buffer'> {\n\tcwd?: string;\n\treadonly env?: Record<string, string | undefined>;\n\treadonly encoding?: TEncoding;\n\t/**\n\t * Decodes non-UTF-8 output. Called when `encoding` is not utf8/binary/buffer.\n\t * Provided by the host via the `GitOptions.decode` option.\n\t * If absent and a non-UTF-8 encoding is requested, throws at runtime.\n\t */\n\treadonly decode?: (data: Uint8Array, options?: { readonly encoding: string }) => string | Promise<string>;\n\t/**\n\t * The size the output buffer to allocate to the spawned process. Set this\n\t * if you are anticipating a large amount of output.\n\t *\n\t * If not specified, this will be 10MB (10485760 bytes) which should be\n\t * enough for most Git operations.\n\t */\n\treadonly maxBuffer?: number;\n\treadonly cancellation?: AbortSignal;\n\t/**\n\t * An optional string or buffer which will be written to\n\t * the child process stdin stream immediately immediately\n\t * after spawning the process.\n\t */\n\treadonly stdin?: string | Buffer;\n\t/**\n\t * The encoding to use when writing to stdin, if the stdin\n\t * parameter is a string.\n\t */\n\treadonly stdinEncoding?: string;\n\treadonly timeout?: number;\n\t/**\n\t * When true, suppresses the `[EXEC]` stderr warning emitted on debug-enabled scopes.\n\t * Use for commands whose failure is expected (e.g. paired with `errors: 'ignore'`).\n\t */\n\treadonly quiet?: boolean;\n}\n\nconst bufferExceededRegex = /stdout maxBuffer( length)? exceeded/;\n\ntype ExitCodeOnlyRunOptions<TEncoding = BufferEncoding | 'buffer'> = RunOptions<TEncoding> & { exitCodeOnly: true };\n\nexport function run(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions: ExitCodeOnlyRunOptions<BufferEncoding>,\n): Promise<number>;\nexport function run(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions?: RunOptions<BufferEncoding>,\n): Promise<string>;\nexport function run<T extends number | string>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions?: RunOptions<BufferEncoding> & { exitCodeOnly?: boolean },\n): Promise<T> {\n\tconst scope = getScopedLogger() ?? maybeStartScopedLogger('Exec.run');\n\n\tconst { stdin, stdinEncoding, cancellation, decode, ...opts }: RunOptions<BufferEncoding> & ExecFileOptions = {\n\t\tmaxBuffer: 1000 * 1024 * 1024,\n\t\t...options,\n\t};\n\n\tconst promise = new Promise<T>((resolve, reject) => {\n\t\tconst proc = execFile(\n\t\t\tcommand,\n\t\t\targs,\n\t\t\t{ ...opts, signal: cancellation },\n\t\t\tasync (error: ExecFileException | null, stdout, stderr) => {\n\t\t\t\tif (options?.exitCodeOnly) {\n\t\t\t\t\tresolve((error?.code ?? proc.exitCode) as T);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (error != null) {\n\t\t\t\t\tif (error.signal === 'SIGTERM') {\n\t\t\t\t\t\treject(\n\t\t\t\t\t\t\tnew CancelledRunError(\n\t\t\t\t\t\t\t\t`${command} ${args.join(' ')}`,\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\terror.code ?? undefined,\n\t\t\t\t\t\t\t\terror.signal,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (bufferExceededRegex.test(error.message)) {\n\t\t\t\t\t\terror.message = `Command output exceeded the allocated stdout buffer. Set 'options.maxBuffer' to a larger value than ${opts.maxBuffer} bytes`;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet stdoutDecoded: string;\n\t\t\t\t\tlet stderrDecoded: string;\n\t\t\t\t\tif (encoding === 'utf8' || encoding === 'binary' || encoding === 'buffer') {\n\t\t\t\t\t\t// stdout & stderr can be `Buffer` or `string\n\t\t\t\t\t\t// oxlint-disable-next-line typescript/no-unnecessary-type-conversion\n\t\t\t\t\t\tstdoutDecoded = stdout.toString();\n\t\t\t\t\t\t// oxlint-disable-next-line typescript/no-unnecessary-type-conversion\n\t\t\t\t\t\tstderrDecoded = stderr.toString();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (decode == null) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstdoutDecoded = await decode(\n\t\t\t\t\t\t\tBuffer.from(stdout, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tstderrDecoded = await decode(\n\t\t\t\t\t\t\tBuffer.from(stderr, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treject(new RunError(error, stdoutDecoded, stderrDecoded));\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (stderr && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\t\tscope?.warn(`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${stderr}`);\n\t\t\t\t}\n\n\t\t\t\tif (encoding === 'utf8' || encoding === 'binary' || encoding === 'buffer') {\n\t\t\t\t\tresolve(stdout as T);\n\t\t\t\t} else {\n\t\t\t\t\tif (decode == null) {\n\t\t\t\t\t\tthrow new Error(`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve(\n\t\t\t\t\t\t(await decode(\n\t\t\t\t\t\t\tBuffer.from(stdout, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t)) as T,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tif (stdin != null) {\n\t\t\tproc.stdin?.end(stdin, (stdinEncoding ?? 'utf8') as BufferEncoding);\n\t\t}\n\t});\n\n\treturn promise.finally(() => scope?.[Symbol.dispose]());\n}\n\nexport interface RunExitResult {\n\t/**\n\t * The process's exit code. ABSENT when the process never exited normally — killed by a signal, in which\n\t * case {@link signal} is set. Deliberately optional rather than defaulted to `0`: a signalled process\n\t * reported as `exitCode: 0` is indistinguishable from a clean success, so callers would read a partial\n\t * or empty stdout as a complete answer.\n\t */\n\treadonly exitCode?: number;\n\t/** Set when the process was terminated by a signal instead of exiting; {@link exitCode} is then absent. */\n\treadonly signal?: NodeJS.Signals;\n}\n\nexport interface RunResult<T extends string | Buffer> extends RunExitResult {\n\tstdout: T;\n\tstderr: T;\n}\n\nexport function runSpawn(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: ExitCodeOnlyRunOptions,\n): Promise<RunExitResult>;\nexport function runSpawn<T extends string | Buffer>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: RunOptions,\n): Promise<RunResult<T>>;\nexport function runSpawn<T extends string | Buffer>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: RunOptions & { exitCodeOnly?: boolean },\n): Promise<RunExitResult | RunResult<T>> {\n\tconst scope = getScopedLogger() ?? maybeStartScopedLogger('Exec.runSpawn');\n\n\tconst { stdin, stdinEncoding, cancellation, decode, ...opts }: RunOptions = options;\n\n\tconst promise = new Promise<RunExitResult | RunResult<T>>((resolve, reject) => {\n\t\tconst proc = spawn(command, args, { ...opts, signal: cancellation });\n\t\tconst errorEncoding = encoding === 'buffer' ? 'utf8' : encoding;\n\n\t\tconst stdoutBuffers: Buffer[] = [];\n\t\tproc.stdout.on('data', (data: Buffer) => stdoutBuffers.push(data));\n\n\t\tconst stderrBuffers: Buffer[] = [];\n\t\tproc.stderr.on('data', (data: Buffer) => stderrBuffers.push(data));\n\n\t\tfunction getStdio<T>(\n\t\t\tencoding: BufferEncoding | 'buffer' | string,\n\t\t): { stdout: T; stderr: T } | Promise<{ stdout: T; stderr: T }> {\n\t\t\tconst stdout = Buffer.concat(stdoutBuffers);\n\t\t\tconst stderr = Buffer.concat(stderrBuffers);\n\t\t\tif (encoding === 'utf8' || encoding === 'binary') {\n\t\t\t\treturn { stdout: stdout.toString(encoding) as T, stderr: stderr.toString(encoding) as T };\n\t\t\t}\n\t\t\tif (encoding === 'buffer') {\n\t\t\t\treturn { stdout: stdout as T, stderr: stderr as T };\n\t\t\t}\n\n\t\t\tif (decode == null) {\n\t\t\t\tthrow new Error(`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`);\n\t\t\t}\n\n\t\t\treturn Promise.all([\n\t\t\t\tdecode(stdout, encoding ? { encoding: encoding } : undefined),\n\t\t\t\tdecode(stderr, encoding ? { encoding: encoding } : undefined),\n\t\t\t]).then(([decodedStdout, decodedStderr]) => ({\n\t\t\t\tstdout: decodedStdout as T,\n\t\t\t\tstderr: decodedStderr as T,\n\t\t\t}));\n\t\t}\n\n\t\tproc.once('error', async ex => {\n\t\t\tif (ex?.name === 'AbortError') {\n\t\t\t\treject(new CancelledRunError(`${command} ${args.join(' ')}`, true));\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst stdio = getStdio<string>(errorEncoding);\n\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\n\t\t\treject(new RunError(ex, stdout, stderr));\n\t\t});\n\n\t\tproc.once('close', async (code, signal) => {\n\t\t\tif (options?.exitCodeOnly) {\n\t\t\t\t// Resolves unconditionally, so this is the one path that can hand back a signalled run. `code`\n\t\t\t\t// is null exactly when the process was killed — report the signal rather than coercing to `0`,\n\t\t\t\t// which would claim a clean success for a command that never finished. Note this returns BEFORE\n\t\t\t\t// the SIGTERM-to-cancellation diversion below, so callers have to classify that themselves.\n\t\t\t\tresolve({ exitCode: code ?? undefined, signal: signal ?? undefined });\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (code !== 0 || signal) {\n\t\t\t\tconst stdio = getStdio<string>(errorEncoding);\n\t\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\t\t\t\tif (stderr.length && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\t\tscope?.warn(`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${stderr}`);\n\t\t\t\t}\n\n\t\t\t\tif (signal === 'SIGTERM') {\n\t\t\t\t\treject(new CancelledRunError(`${command} ${args.join(' ')}`, true, code ?? undefined, signal));\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\treject(\n\t\t\t\t\tnew RunError(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmessage: `Command failed with exit code ${code}`,\n\t\t\t\t\t\t\tcode: code,\n\t\t\t\t\t\t\tsignal: signal ?? undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstdout,\n\t\t\t\t\t\tstderr,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst stdio = getStdio<T>(encoding);\n\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\t\t\tif (stderr.length && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\tscope?.warn(\n\t\t\t\t\t`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${typeof stderr === 'string' ? stderr : stderr.toString()}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// The guard above already rejected every non-zero and every signalled close, so this is a clean\n\t\t\t// zero exit — `code` cannot be null here. (The optional typing exists for the `exitCodeOnly`\n\t\t\t// branch, which is where a codeless result can genuinely surface.)\n\t\t\tresolve({ exitCode: code ?? undefined, signal: signal ?? undefined, stdout: stdout, stderr: stderr });\n\t\t});\n\n\t\tif (stdin) {\n\t\t\tif (typeof stdin === 'string') {\n\t\t\t\tproc.stdin.end(stdin, (stdinEncoding ?? 'utf8') as BufferEncoding);\n\t\t\t} else if (stdin instanceof Buffer) {\n\t\t\t\tproc.stdin.end(stdin);\n\t\t\t}\n\t\t}\n\t});\n\n\treturn promise.finally(() => scope?.[Symbol.dispose]());\n}\n\nexport async function fsExists(path: string): Promise<boolean> {\n\treturn new Promise<boolean>(resolve => access(path, constants.F_OK, err => resolve(err == null)));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"exec.js","names":["joinPaths"],"sources":["../../../../../utils/src/env/node/exec.ts"],"sourcesContent":["import type { ExecFileException, ExecFileOptions } from 'child_process';\nimport { exec, execFile, spawn } from 'child_process';\nimport type { Stats } from 'fs';\nimport { access, constants } from 'fs';\nimport { stat } from 'fs/promises';\nimport { join as joinPaths } from 'path';\nimport * as process from 'process';\nimport { getScopedLogger, maybeStartScopedLogger } from '../../logger.scoped.js';\nimport { normalizePath } from '../../path.js';\nimport { isWindows } from './platform.js';\n\n// -- Error types --\n\ninterface RunErrorContext {\n\tmessage: string;\n\tcmd?: string | undefined;\n\tkilled?: boolean | undefined;\n\tcode?: string | number | null | undefined;\n\tsignal?: NodeJS.Signals | undefined;\n}\n\nexport class RunError extends Error {\n\treadonly cmd?: string | undefined;\n\treadonly killed?: boolean | undefined;\n\treadonly code?: string | number | undefined;\n\treadonly signal?: NodeJS.Signals | undefined;\n\treadonly stdout: string;\n\treadonly stderr: string;\n\n\tconstructor(context: RunErrorContext, stdout: string, stderr: string) {\n\t\tsuper(context.message);\n\n\t\tthis.cmd = context.cmd;\n\t\tthis.killed = context.killed;\n\t\tthis.code = context.code ?? undefined;\n\t\tthis.signal = context.signal;\n\t\tthis.stdout = stdout?.trim() ?? '';\n\t\tthis.stderr = stderr?.trim() ?? '';\n\n\t\tthis.name = 'RunError';\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\nexport class CancelledRunError extends RunError {\n\tconstructor(cmd: string, killed: boolean, code?: number | string | undefined, signal: NodeJS.Signals = 'SIGTERM') {\n\t\tsuper(\n\t\t\t{ message: `Operation cancelled; command=${cmd}`, cmd: cmd, killed: killed, code: code, signal: signal },\n\t\t\t'',\n\t\t\t'',\n\t\t);\n\n\t\tthis.name = 'CancelledRunError';\n\t\tError.captureStackTrace?.(this, new.target);\n\t}\n}\n\n// -- Execution utilities --\n\nconst slashesRegex = /[\\\\/]/;\nconst ps1Regex = /\\.ps1$/i;\nconst batOrCmdRegex = /\\.(bat|cmd)$/i;\nconst jsRegex = /\\.(js)$/i;\n\n/**\n * Search PATH to see if a file exists in any of the path folders.\n *\n * @param {string} exe The file to search for\n * @return {string} A fully qualified path, or the original path if nothing\n * is found\n *\n * @private\n */\nasync function runDownPath(exe: string): Promise<string> {\n\t// NB: Windows won't search PATH looking for executables in spawn like\n\t// Posix does\n\n\t// Files with any directory path don't get this applied\n\tif (slashesRegex.test(exe)) return exe;\n\n\tconst target = joinPaths('.', exe);\n\ttry {\n\t\tconst stats = await stat(target);\n\t\tif (stats?.isFile() && isExecutable(stats)) return target;\n\t} catch {}\n\n\tconst path = process.env.PATH;\n\tif (path != null && path.length !== 0) {\n\t\tconst haystack = path.split(isWindows ? ';' : ':');\n\t\tfor (const p of haystack) {\n\t\t\tconst needle = joinPaths(p, exe);\n\t\t\ttry {\n\t\t\t\tconst stats = await stat(needle);\n\t\t\t\tif (stats?.isFile() && isExecutable(stats)) return needle;\n\t\t\t} catch {}\n\t\t}\n\t}\n\n\treturn exe;\n}\n\nfunction isExecutable(stats: Stats) {\n\tif (isWindows) return true;\n\n\tconst isGroup = stats.gid ? stats.gid === process.getgid?.() : true;\n\tconst isUser = stats.uid ? stats.uid === process.getuid?.() : true;\n\n\treturn Boolean(stats.mode & 0o0001 || (stats.mode & 0o0010 && isGroup) || (stats.mode & 0o0100 && isUser));\n}\n\n/**\n * Finds the executable and parameters to run on Windows. This method\n * mimics the POSIX behavior of being able to run scripts as executables by\n * replacing the passed-in executable with the script runner, for PowerShell,\n * CMD, and node scripts.\n *\n * This method also does the work of running down PATH, which spawn on Windows\n * also doesn't do, unlike on POSIX.\n */\nexport async function findExecutable(exe: string, args: string[]): Promise<{ cmd: string; args: string[] }> {\n\t// POSIX can just execute scripts directly, no need for silly goosery\n\tif (!isWindows) return { cmd: await runDownPath(exe), args: args };\n\n\tif (!(await fsExists(exe))) {\n\t\t// NB: When you write something like `surf-client ... -- surf-build` on Windows,\n\t\t// a shell would normally convert that to surf-build.cmd, but since it's passed\n\t\t// in as an argument, it doesn't happen\n\t\tconst possibleExts = ['.exe', '.bat', '.cmd', '.ps1'];\n\t\tfor (const ext of possibleExts) {\n\t\t\tconst possibleFullPath = await runDownPath(`${exe}${ext}`);\n\n\t\t\tif (await fsExists(possibleFullPath)) return findExecutable(possibleFullPath, args);\n\t\t}\n\t}\n\n\tif (ps1Regex.test(exe)) {\n\t\tconst cmd = joinPaths(\n\t\t\tprocess.env.SYSTEMROOT ?? 'C:\\\\WINDOWS',\n\t\t\t'System32',\n\t\t\t'WindowsPowerShell',\n\t\t\t'v1.0',\n\t\t\t'PowerShell.exe',\n\t\t);\n\t\tconst psargs = ['-ExecutionPolicy', 'Unrestricted', '-NoLogo', '-NonInteractive', '-File', exe];\n\n\t\treturn { cmd: cmd, args: [...psargs, ...args] };\n\t}\n\n\tif (batOrCmdRegex.test(exe)) {\n\t\tconst cmd = joinPaths(process.env.SYSTEMROOT ?? 'C:\\\\WINDOWS', 'System32', 'cmd.exe');\n\t\tconst cmdArgs = ['/C', exe, ...args];\n\n\t\treturn { cmd: cmd, args: cmdArgs };\n\t}\n\n\tif (jsRegex.test(exe)) {\n\t\tconst cmd = process.execPath;\n\t\tconst nodeArgs = [exe];\n\n\t\treturn { cmd: cmd, args: [...nodeArgs, ...args] };\n\t}\n\n\treturn { cmd: exe, args: args };\n}\n\nexport async function getWindowsShortPath(path: string): Promise<string> {\n\treturn new Promise<string>((resolve, reject) => {\n\t\texec(`for %I in (\"${path}\") do @echo %~sI`, (error, stdout, _stderr) => {\n\t\t\tif (error != null) {\n\t\t\t\treject(error);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tresolve(normalizePath(stdout.trim()));\n\t\t});\n\t});\n}\n\nexport interface RunOptions<TEncoding = BufferEncoding | 'buffer'> {\n\tcwd?: string;\n\treadonly env?: Record<string, string | undefined>;\n\treadonly encoding?: TEncoding;\n\t/**\n\t * Decodes non-UTF-8 output. Called when `encoding` is not utf8/binary/buffer.\n\t * Provided by the host via the `GitOptions.decode` option.\n\t * If absent and a non-UTF-8 encoding is requested, throws at runtime.\n\t */\n\treadonly decode?: (data: Uint8Array, options?: { readonly encoding: string }) => string | Promise<string>;\n\t/**\n\t * The size the output buffer to allocate to the spawned process. Set this\n\t * if you are anticipating a large amount of output.\n\t *\n\t * If not specified, this will be 10MB (10485760 bytes) which should be\n\t * enough for most Git operations.\n\t */\n\treadonly maxBuffer?: number;\n\treadonly cancellation?: AbortSignal;\n\t/**\n\t * An optional string or buffer which will be written to\n\t * the child process stdin stream immediately immediately\n\t * after spawning the process.\n\t */\n\treadonly stdin?: string | Buffer;\n\t/**\n\t * The encoding to use when writing to stdin, if the stdin\n\t * parameter is a string.\n\t */\n\treadonly stdinEncoding?: string;\n\treadonly timeout?: number;\n\t/**\n\t * When true, suppresses the `[EXEC]` stderr warning emitted on debug-enabled scopes.\n\t * Use for commands whose failure is expected (e.g. paired with `errors: 'ignore'`).\n\t */\n\treadonly quiet?: boolean;\n}\n\nconst bufferExceededRegex = /stdout maxBuffer( length)? exceeded/;\n\ntype ExitCodeOnlyRunOptions<TEncoding = BufferEncoding | 'buffer'> = RunOptions<TEncoding> & { exitCodeOnly: true };\n\nexport function run(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions: ExitCodeOnlyRunOptions<BufferEncoding>,\n): Promise<number>;\nexport function run(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions?: RunOptions<BufferEncoding>,\n): Promise<string>;\nexport function run<T extends number | string>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | string,\n\toptions?: RunOptions<BufferEncoding> & { exitCodeOnly?: boolean },\n): Promise<T> {\n\tconst scope = getScopedLogger() ?? maybeStartScopedLogger('Exec.run');\n\n\tconst { stdin, stdinEncoding, cancellation, decode, ...opts }: RunOptions<BufferEncoding> & ExecFileOptions = {\n\t\tmaxBuffer: 1000 * 1024 * 1024,\n\t\t...options,\n\t};\n\n\tconst promise = new Promise<T>((resolve, reject) => {\n\t\tconst proc = execFile(\n\t\t\tcommand,\n\t\t\targs,\n\t\t\t{ ...opts, signal: cancellation },\n\t\t\tasync (error: ExecFileException | null, stdout, stderr) => {\n\t\t\t\tif (options?.exitCodeOnly) {\n\t\t\t\t\tresolve((error?.code ?? proc.exitCode) as T);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (error != null) {\n\t\t\t\t\tif (error.signal === 'SIGTERM') {\n\t\t\t\t\t\treject(\n\t\t\t\t\t\t\tnew CancelledRunError(\n\t\t\t\t\t\t\t\t`${command} ${args.join(' ')}`,\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\terror.code ?? undefined,\n\t\t\t\t\t\t\t\terror.signal,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (bufferExceededRegex.test(error.message)) {\n\t\t\t\t\t\terror.message = `Command output exceeded the allocated stdout buffer. Set 'options.maxBuffer' to a larger value than ${opts.maxBuffer} bytes`;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet stdoutDecoded: string;\n\t\t\t\t\tlet stderrDecoded: string;\n\t\t\t\t\tif (encoding === 'utf8' || encoding === 'binary' || encoding === 'buffer') {\n\t\t\t\t\t\t// stdout & stderr can be `Buffer` or `string\n\t\t\t\t\t\t// oxlint-disable-next-line typescript/no-unnecessary-type-conversion\n\t\t\t\t\t\tstdoutDecoded = stdout.toString();\n\t\t\t\t\t\t// oxlint-disable-next-line typescript/no-unnecessary-type-conversion\n\t\t\t\t\t\tstderrDecoded = stderr.toString();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (decode == null) {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstdoutDecoded = await decode(\n\t\t\t\t\t\t\tBuffer.from(stdout, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tstderrDecoded = await decode(\n\t\t\t\t\t\t\tBuffer.from(stderr, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treject(new RunError(error, stdoutDecoded, stderrDecoded));\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (stderr && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\t\tscope?.warn(`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${stderr}`);\n\t\t\t\t}\n\n\t\t\t\tif (encoding === 'utf8' || encoding === 'binary' || encoding === 'buffer') {\n\t\t\t\t\tresolve(stdout as T);\n\t\t\t\t} else {\n\t\t\t\t\tif (decode == null) {\n\t\t\t\t\t\tthrow new Error(`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`);\n\t\t\t\t\t}\n\n\t\t\t\t\tresolve(\n\t\t\t\t\t\t(await decode(\n\t\t\t\t\t\t\tBuffer.from(stdout, 'binary'),\n\t\t\t\t\t\t\tencoding ? { encoding: encoding } : undefined,\n\t\t\t\t\t\t)) as T,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t);\n\n\t\tif (stdin != null) {\n\t\t\tproc.stdin?.end(stdin, (stdinEncoding ?? 'utf8') as BufferEncoding);\n\t\t}\n\t});\n\n\treturn promise.finally(() => scope?.[Symbol.dispose]());\n}\n\nexport interface RunExitResult {\n\t/**\n\t * The process's exit code. ABSENT when the process never exited normally — killed by a signal, in which\n\t * case {@link signal} is set. Deliberately optional rather than defaulted to `0`: a signalled process\n\t * reported as `exitCode: 0` is indistinguishable from a clean success, so callers would read a partial\n\t * or empty stdout as a complete answer.\n\t */\n\treadonly exitCode?: number;\n\t/** Set when the process was terminated by a signal instead of exiting; {@link exitCode} is then absent. */\n\treadonly signal?: NodeJS.Signals;\n}\n\nexport interface RunResult<T extends string | Buffer> extends RunExitResult {\n\tstdout: T;\n\tstderr: T;\n}\n\nexport function runSpawn(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: ExitCodeOnlyRunOptions,\n): Promise<RunExitResult>;\nexport function runSpawn<T extends string | Buffer>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: RunOptions,\n): Promise<RunResult<T>>;\nexport function runSpawn<T extends string | Buffer>(\n\tcommand: string,\n\targs: readonly string[],\n\tencoding: BufferEncoding | 'buffer' | string,\n\toptions: RunOptions & { exitCodeOnly?: boolean },\n): Promise<RunExitResult | RunResult<T>> {\n\tconst scope = getScopedLogger() ?? maybeStartScopedLogger('Exec.runSpawn');\n\n\tconst { stdin, stdinEncoding, cancellation, decode, ...opts }: RunOptions = options;\n\n\tconst promise = new Promise<RunExitResult | RunResult<T>>((resolve, reject) => {\n\t\tconst proc = spawn(command, args, { ...opts, signal: cancellation });\n\t\tconst errorEncoding = encoding === 'buffer' ? 'utf8' : encoding;\n\n\t\tconst stdoutBuffers: Buffer[] = [];\n\t\tproc.stdout.on('data', (data: Buffer) => stdoutBuffers.push(data));\n\n\t\tconst stderrBuffers: Buffer[] = [];\n\t\tproc.stderr.on('data', (data: Buffer) => stderrBuffers.push(data));\n\n\t\tfunction getStdio<T>(\n\t\t\tencoding: BufferEncoding | 'buffer' | string,\n\t\t): { stdout: T; stderr: T } | Promise<{ stdout: T; stderr: T }> {\n\t\t\tconst stdout = Buffer.concat(stdoutBuffers);\n\t\t\tconst stderr = Buffer.concat(stderrBuffers);\n\t\t\tif (encoding === 'utf8' || encoding === 'binary') {\n\t\t\t\treturn { stdout: stdout.toString(encoding) as T, stderr: stderr.toString(encoding) as T };\n\t\t\t}\n\t\t\tif (encoding === 'buffer') {\n\t\t\t\treturn { stdout: stdout as T, stderr: stderr as T };\n\t\t\t}\n\n\t\t\tif (decode == null) {\n\t\t\t\tthrow new Error(`Non-UTF-8 encoding '${encoding}' requested but no decode function configured`);\n\t\t\t}\n\n\t\t\treturn Promise.all([\n\t\t\t\tdecode(stdout, encoding ? { encoding: encoding } : undefined),\n\t\t\t\tdecode(stderr, encoding ? { encoding: encoding } : undefined),\n\t\t\t]).then(([decodedStdout, decodedStderr]) => ({\n\t\t\t\tstdout: decodedStdout as T,\n\t\t\t\tstderr: decodedStderr as T,\n\t\t\t}));\n\t\t}\n\n\t\tproc.once('error', async ex => {\n\t\t\tif (ex?.name === 'AbortError') {\n\t\t\t\treject(new CancelledRunError(`${command} ${args.join(' ')}`, true));\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst stdio = getStdio<string>(errorEncoding);\n\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\n\t\t\treject(new RunError(ex, stdout, stderr));\n\t\t});\n\n\t\tproc.once('close', async (code, signal) => {\n\t\t\tif (options?.exitCodeOnly) {\n\t\t\t\t// Resolves unconditionally, so this is the one path that can hand back a signalled run. `code`\n\t\t\t\t// is null exactly when the process was killed — report the signal rather than coercing to `0`,\n\t\t\t\t// which would claim a clean success for a command that never finished. Note this returns BEFORE\n\t\t\t\t// the SIGTERM-to-cancellation diversion below, so callers have to classify that themselves.\n\t\t\t\tresolve({ exitCode: code ?? undefined, signal: signal ?? undefined });\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (code !== 0 || signal) {\n\t\t\t\tconst stdio = getStdio<string>(errorEncoding);\n\t\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\t\t\t\tif (stderr.length && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\t\tscope?.warn(`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${stderr}`);\n\t\t\t\t}\n\n\t\t\t\tif (signal === 'SIGTERM') {\n\t\t\t\t\treject(new CancelledRunError(`${command} ${args.join(' ')}`, true, code ?? undefined, signal));\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\treject(\n\t\t\t\t\tnew RunError(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmessage: `Command failed with exit code ${code}`,\n\t\t\t\t\t\t\tcode: code,\n\t\t\t\t\t\t\tsignal: signal ?? undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tstdout,\n\t\t\t\t\t\tstderr,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst stdio = getStdio<T>(encoding);\n\t\t\tconst { stdout, stderr } = stdio instanceof Promise ? await stdio : stdio;\n\t\t\tif (stderr.length && !options?.quiet && scope?.enabled('debug')) {\n\t\t\t\tscope?.warn(\n\t\t\t\t\t`[EXEC] '${command} ${args.join(' ')}' \\u2022 ${typeof stderr === 'string' ? stderr : stderr.toString()}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// The guard above already rejected every non-zero and every signalled close, so this is a clean\n\t\t\t// zero exit — `code` cannot be null here. (The optional typing exists for the `exitCodeOnly`\n\t\t\t// branch, which is where a codeless result can genuinely surface.)\n\t\t\tresolve({ exitCode: code ?? undefined, signal: signal ?? undefined, stdout: stdout, stderr: stderr });\n\t\t});\n\n\t\tif (stdin != null) {\n\t\t\tif (typeof stdin === 'string') {\n\t\t\t\tproc.stdin.end(stdin, (stdinEncoding ?? 'utf8') as BufferEncoding);\n\t\t\t} else if (stdin instanceof Buffer) {\n\t\t\t\tproc.stdin.end(stdin);\n\t\t\t}\n\t\t}\n\t});\n\n\treturn promise.finally(() => scope?.[Symbol.dispose]());\n}\n\nexport async function fsExists(path: string): Promise<boolean> {\n\treturn new Promise<boolean>(resolve => access(path, constants.F_OK, err => resolve(err == null)));\n}\n"],"mappings":";;;;;;;;;AAqBA,IAAa,WAAb,cAA8B,MAAM;CACnC;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,SAA0B,QAAgB,QAAgB;EACrE,MAAM,QAAQ,OAAO;EAErB,KAAK,MAAM,QAAQ;EACnB,KAAK,SAAS,QAAQ;EACtB,KAAK,OAAO,QAAQ,QAAQ,KAAA;EAC5B,KAAK,SAAS,QAAQ;EACtB,KAAK,SAAS,QAAQ,KAAK,KAAK;EAChC,KAAK,SAAS,QAAQ,KAAK,KAAK;EAEhC,KAAK,OAAO;EACZ,MAAM,oBAAoB,MAAM,UAAU;CAC3C;AACD;AAEA,IAAa,oBAAb,cAAuC,SAAS;CAC/C,YAAY,KAAa,QAAiB,MAAoC,SAAyB,WAAW;EACjH,MACC;GAAE,SAAS,gCAAgC;GAAY;GAAa;GAAc;GAAc;EAAO,GACvG,IACA,EACD;EAEA,KAAK,OAAO;EACZ,MAAM,oBAAoB,MAAM,UAAU;CAC3C;AACD;AAIA,MAAM,eAAe;AACrB,MAAM,WAAW;AACjB,MAAM,gBAAgB;AACtB,MAAM,UAAU;;;;;;;;;;AAWhB,eAAe,YAAY,KAA8B;CAKxD,IAAI,aAAa,KAAK,GAAG,GAAG,OAAO;CAEnC,MAAM,SAASA,KAAU,KAAK,GAAG;CACjC,IAAI;EACH,MAAM,QAAQ,MAAM,KAAK,MAAM;EAC/B,IAAI,OAAO,OAAO,KAAK,aAAa,KAAK,GAAG,OAAO;CACpD,QAAQ,CAAC;CAET,MAAM,OAAO,QAAQ,IAAI;CACzB,IAAI,QAAQ,QAAQ,KAAK,WAAW,GAAG;EACtC,MAAM,WAAW,KAAK,MAAM,YAAY,MAAM,GAAG;EACjD,KAAK,MAAM,KAAK,UAAU;GACzB,MAAM,SAASA,KAAU,GAAG,GAAG;GAC/B,IAAI;IACH,MAAM,QAAQ,MAAM,KAAK,MAAM;IAC/B,IAAI,OAAO,OAAO,KAAK,aAAa,KAAK,GAAG,OAAO;GACpD,QAAQ,CAAC;EACV;CACD;CAEA,OAAO;AACR;AAEA,SAAS,aAAa,OAAc;CACnC,IAAI,WAAW,OAAO;CAEtB,MAAM,UAAU,MAAM,MAAM,MAAM,QAAQ,QAAQ,SAAS,IAAI;CAC/D,MAAM,SAAS,MAAM,MAAM,MAAM,QAAQ,QAAQ,SAAS,IAAI;CAE9D,OAAO,QAAQ,MAAM,OAAO,KAAW,MAAM,OAAO,KAAU,WAAa,MAAM,OAAO,MAAU,MAAO;AAC1G;;;;;;;;;;AAWA,eAAsB,eAAe,KAAa,MAA0D;CAE3G,IAAI,CAAC,WAAW,OAAO;EAAE,KAAK,MAAM,YAAY,GAAG;EAAS;CAAK;CAEjE,IAAI,CAAE,MAAM,SAAS,GAAG,GAKvB,KAAK,MAAM,OAAO;EADI;EAAQ;EAAQ;EAAQ;CACjB,GAAG;EAC/B,MAAM,mBAAmB,MAAM,YAAY,GAAG,MAAM,KAAK;EAEzD,IAAI,MAAM,SAAS,gBAAgB,GAAG,OAAO,eAAe,kBAAkB,IAAI;CACnF;CAGD,IAAI,SAAS,KAAK,GAAG,GAUpB,OAAO;EAAE,KATGA,KACX,QAAQ,IAAI,cAAc,eAC1B,YACA,qBACA,QACA,gBAIe;EAAG,MAAM,CAAC,GAAG;GAFb;GAAoB;GAAgB;GAAW;GAAmB;GAAS;EAEzD,GAAG,GAAG,IAAI;CAAE;CAG/C,IAAI,cAAc,KAAK,GAAG,GAIzB,OAAO;EAAE,KAHGA,KAAU,QAAQ,IAAI,cAAc,eAAe,YAAY,SAG3D;EAAG,MAAM;GAFR;GAAM;GAAK,GAAG;EAEA;CAAE;CAGlC,IAAI,QAAQ,KAAK,GAAG,GAInB,OAAO;EAAE,KAHG,QAAQ;EAGD,MAAM,CAAC,GAAG,CAFX,GAEkB,GAAG,GAAG,IAAI;CAAE;CAGjD,OAAO;EAAE,KAAK;EAAW;CAAK;AAC/B;AAEA,eAAsB,oBAAoB,MAA+B;CACxE,OAAO,IAAI,SAAiB,SAAS,WAAW;EAC/C,KAAK,eAAe,KAAK,oBAAoB,OAAO,QAAQ,YAAY;GACvE,IAAI,SAAS,MAAM;IAClB,OAAO,KAAK;IACZ;GACD;GAEA,QAAQ,cAAc,OAAO,KAAK,CAAC,CAAC;EACrC,CAAC;CACF,CAAC;AACF;AAwCA,MAAM,sBAAsB;AAgB5B,SAAgB,IACf,SACA,MACA,UACA,SACa;CACb,MAAM,QAAQ,gBAAgB,KAAK,uBAAuB,UAAU;CAEpE,MAAM,EAAE,OAAO,eAAe,cAAc,QAAQ,GAAG,SAAuD;EAC7G,WAAW;EACX,GAAG;CACJ;CAuFA,OAAO,IArFa,SAAY,SAAS,WAAW;EACnD,MAAM,OAAO,SACZ,SACA,MACA;GAAE,GAAG;GAAM,QAAQ;EAAa,GAChC,OAAO,OAAiC,QAAQ,WAAW;GAC1D,IAAI,SAAS,cAAc;IAC1B,QAAS,OAAO,QAAQ,KAAK,QAAc;IAE3C;GACD;GAEA,IAAI,SAAS,MAAM;IAClB,IAAI,MAAM,WAAW,WAAW;KAC/B,OACC,IAAI,kBACH,GAAG,QAAQ,GAAG,KAAK,KAAK,GAAG,KAC3B,MACA,MAAM,QAAQ,KAAA,GACd,MAAM,MACP,CACD;KAEA;IACD;IAEA,IAAI,oBAAoB,KAAK,MAAM,OAAO,GACzC,MAAM,UAAU,uGAAuG,KAAK,UAAU;IAGvI,IAAI;IACJ,IAAI;IACJ,IAAI,aAAa,UAAU,aAAa,YAAY,aAAa,UAAU;KAG1E,gBAAgB,OAAO,SAAS;KAEhC,gBAAgB,OAAO,SAAS;IACjC,OAAO;KACN,IAAI,UAAU,MACb,MAAM,IAAI,MACT,uBAAuB,SAAS,8CACjC;KAGD,gBAAgB,MAAM,OACrB,OAAO,KAAK,QAAQ,QAAQ,GAC5B,WAAW,EAAY,SAAS,IAAI,KAAA,CACrC;KACA,gBAAgB,MAAM,OACrB,OAAO,KAAK,QAAQ,QAAQ,GAC5B,WAAW,EAAY,SAAS,IAAI,KAAA,CACrC;IACD;IACA,OAAO,IAAI,SAAS,OAAO,eAAe,aAAa,CAAC;IAExD;GACD;GAEA,IAAI,UAAU,CAAC,SAAS,SAAS,OAAO,QAAQ,OAAO,GACtD,OAAO,KAAK,WAAW,QAAQ,GAAG,KAAK,KAAK,GAAG,EAAE,WAAW,QAAQ;GAGrE,IAAI,aAAa,UAAU,aAAa,YAAY,aAAa,UAChE,QAAQ,MAAW;QACb;IACN,IAAI,UAAU,MACb,MAAM,IAAI,MAAM,uBAAuB,SAAS,8CAA8C;IAG/F,QACE,MAAM,OACN,OAAO,KAAK,QAAQ,QAAQ,GAC5B,WAAW,EAAY,SAAS,IAAI,KAAA,CACrC,CACD;GACD;EACD,CACD;EAEA,IAAI,SAAS,MACZ,KAAK,OAAO,IAAI,OAAQ,iBAAiB,MAAyB;CAEpE,CAEa,CAAC,CAAC,cAAc,QAAQ,OAAO,QAAQ,CAAC,CAAC;AACvD;AA+BA,SAAgB,SACf,SACA,MACA,UACA,SACwC;CACxC,MAAM,QAAQ,gBAAgB,KAAK,uBAAuB,eAAe;CAEzE,MAAM,EAAE,OAAO,eAAe,cAAc,QAAQ,GAAG,SAAqB;CAgH5E,OAAO,IA9Ga,SAAuC,SAAS,WAAW;EAC9E,MAAM,OAAO,MAAM,SAAS,MAAM;GAAE,GAAG;GAAM,QAAQ;EAAa,CAAC;EACnE,MAAM,gBAAgB,aAAa,WAAW,SAAS;EAEvD,MAAM,gBAA0B,CAAC;EACjC,KAAK,OAAO,GAAG,SAAS,SAAiB,cAAc,KAAK,IAAI,CAAC;EAEjE,MAAM,gBAA0B,CAAC;EACjC,KAAK,OAAO,GAAG,SAAS,SAAiB,cAAc,KAAK,IAAI,CAAC;EAEjE,SAAS,SACR,UAC+D;GAC/D,MAAM,SAAS,OAAO,OAAO,aAAa;GAC1C,MAAM,SAAS,OAAO,OAAO,aAAa;GAC1C,IAAI,aAAa,UAAU,aAAa,UACvC,OAAO;IAAE,QAAQ,OAAO,SAAS,QAAQ;IAAQ,QAAQ,OAAO,SAAS,QAAQ;GAAO;GAEzF,IAAI,aAAa,UAChB,OAAO;IAAU;IAAqB;GAAY;GAGnD,IAAI,UAAU,MACb,MAAM,IAAI,MAAM,uBAAuB,SAAS,8CAA8C;GAG/F,OAAO,QAAQ,IAAI,CAClB,OAAO,QAAQ,WAAW,EAAY,SAAS,IAAI,KAAA,CAAS,GAC5D,OAAO,QAAQ,WAAW,EAAY,SAAS,IAAI,KAAA,CAAS,CAC7D,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,oBAAoB;IAC5C,QAAQ;IACR,QAAQ;GACT,EAAE;EACH;EAEA,KAAK,KAAK,SAAS,OAAM,OAAM;GAC9B,IAAI,IAAI,SAAS,cAAc;IAC9B,OAAO,IAAI,kBAAkB,GAAG,QAAQ,GAAG,KAAK,KAAK,GAAG,KAAK,IAAI,CAAC;IAElE;GACD;GAEA,MAAM,QAAQ,SAAiB,aAAa;GAC5C,MAAM,EAAE,QAAQ,WAAW,iBAAiB,UAAU,MAAM,QAAQ;GAEpE,OAAO,IAAI,SAAS,IAAI,QAAQ,MAAM,CAAC;EACxC,CAAC;EAED,KAAK,KAAK,SAAS,OAAO,MAAM,WAAW;GAC1C,IAAI,SAAS,cAAc;IAK1B,QAAQ;KAAE,UAAU,QAAQ,KAAA;KAAW,QAAQ,UAAU,KAAA;IAAU,CAAC;IAEpE;GACD;GAEA,IAAI,SAAS,KAAK,QAAQ;IACzB,MAAM,QAAQ,SAAiB,aAAa;IAC5C,MAAM,EAAE,QAAQ,WAAW,iBAAiB,UAAU,MAAM,QAAQ;IACpE,IAAI,OAAO,UAAU,CAAC,SAAS,SAAS,OAAO,QAAQ,OAAO,GAC7D,OAAO,KAAK,WAAW,QAAQ,GAAG,KAAK,KAAK,GAAG,EAAE,WAAW,QAAQ;IAGrE,IAAI,WAAW,WAAW;KACzB,OAAO,IAAI,kBAAkB,GAAG,QAAQ,GAAG,KAAK,KAAK,GAAG,KAAK,MAAM,QAAQ,KAAA,GAAW,MAAM,CAAC;KAE7F;IACD;IAEA,OACC,IAAI,SACH;KACC,SAAS,iCAAiC;KACpC;KACN,QAAQ,UAAU,KAAA;IACnB,GACA,QACA,MACD,CACD;IAEA;GACD;GAEA,MAAM,QAAQ,SAAY,QAAQ;GAClC,MAAM,EAAE,QAAQ,WAAW,iBAAiB,UAAU,MAAM,QAAQ;GACpE,IAAI,OAAO,UAAU,CAAC,SAAS,SAAS,OAAO,QAAQ,OAAO,GAC7D,OAAO,KACN,WAAW,QAAQ,GAAG,KAAK,KAAK,GAAG,EAAE,WAAW,OAAO,WAAW,WAAW,SAAS,OAAO,SAAS,GACvG;GAMD,QAAQ;IAAE,UAAU,QAAQ,KAAA;IAAW,QAAQ,UAAU,KAAA;IAAmB;IAAgB;GAAO,CAAC;EACrG,CAAC;EAED,IAAI,SAAS,MAAM;GAClB,IAAI,OAAO,UAAU,UACpB,KAAK,MAAM,IAAI,OAAQ,iBAAiB,MAAyB;QAC3D,IAAI,iBAAiB,QAC3B,KAAK,MAAM,IAAI,KAAK;EAEtB;CACD,CAEa,CAAC,CAAC,cAAc,QAAQ,OAAO,QAAQ,CAAC,CAAC;AACvD;AAEA,eAAsB,SAAS,MAAgC;CAC9D,OAAO,IAAI,SAAiB,YAAW,OAAO,MAAM,UAAU,OAAM,QAAO,QAAQ,OAAO,IAAI,CAAC,CAAC;AACjG"}
@@ -113,42 +113,87 @@ provider before calling the token backend; never reuse an id discovered under a
113
113
  Every read returns `ProviderResult<T>` (`items` + `warnings` + `fetchFailed?`), and every paged read extends
114
114
  it with `page` + `hasMore` + `cursor?`. **No read throws for a provider-side failure** — see §6.
115
115
 
116
- | Method | Returns | Scope |
117
- | ---------------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------- |
118
- | `listOrgs` | `ProviderOrganization` | Orgs / workspaces / groups / Bitbucket DC projects; issue-tracker resources (Jira sites, …). |
119
- | `listProjects` | `ProviderOrganization` | The project tier: Azure DevOps, and issue-tracker projects. |
120
- | `listRepos` | `ProviderRepositoryShape` | Repos of an `org`, or account-wide user-affiliated repos when `org` is omitted. |
121
- | `listPullRequestsPage` | `PullRequestShape` | With `repos`: those repos' PRs. Without: the user's PRs account-wide. |
122
- | `searchPullRequestsPage` | `PullRequestShape` | PRs involving the user that match structured criteria, optionally repo/org-scoped. |
123
- | `countPullRequests` | `PullRequestCountResult` | How many PRs match each scope, fetching none where the provider can count. See §5.1. |
124
- | `listIssuesPage` | `IssueShape` | Same split, for a **git host**'s issues. |
125
- | `searchIssuesPage` | `IssueShape` | Issues matching structured criteria over a repo/org scope — **no** `@me` binding. |
126
- | `countIssues` | `IssueCountResult` | How many match each scope, fetching none of them. See §5.1. |
127
- | `getIssuesBatch` | `IssueBatchResult` | Resolves N `(owner, repo, number)` coordinates in one request; an absence is proven. |
128
- | `getTrackerIssue` | `TrackerIssueResult` | Resolves ONE tracker issue by key within a resource; an absence is proven. Jira (Cloud + Data Center) / Linear. |
129
- | `listIssueTrackerIssuesPage` | `IssueShape` | Jira (Cloud + Data Center) / Linear / Trello (issues live under resource → project). |
130
- | `sweepPullRequests` | `ProviderSweepResult` | Drains **every** page across providers (`maxPages`, default 100). |
131
- | `sweepClosedPullRequests` | `ProviderSweepResult` | Same, pinned to `['closed','merged']`. |
132
- | `broadenIssues` | `ProviderBroadenResult` | Per-org fan-out for every visible issue, unfiltered by assignee. |
133
- | `resolveRepository` | `ResolveRepositoryResult` | Remote URL → canonical provider identity (the `gk repo resolve` equivalent). |
134
- | `getSupportedFilters` | filter capability table | Static, connection-free. See §7. |
116
+ | Method | Returns | Scope |
117
+ | ---------------------------- | ------------------------- | -------------------------------------------------------------------------------------------- |
118
+ | `listOrgs` | `ProviderOrganization` | Orgs / workspaces / groups / Bitbucket DC projects; issue-tracker resources (Jira sites, …). |
119
+ | `listProjects` | `ProviderOrganization` | The project tier: Azure DevOps, and issue-tracker projects. |
120
+ | `listRepos` | `ProviderRepositoryShape` | Repos of an `org`, or account-wide user-affiliated repos when `org` is omitted. |
121
+ | `listPullRequestsPage` | `PullRequestShape` | With `repos`: those repos' PRs. Without: the user's PRs account-wide. |
122
+ | `searchPullRequestsPage` | `PullRequestShape` | PRs involving the user that match structured criteria, optionally repo/org-scoped. |
123
+ | `countPullRequests` | `PullRequestCountResult` | How many PRs match each scope, fetching none where the provider can count. See §5.1. |
124
+ | `listIssuesPage` | `IssueShape` | Same split, for a **git host**'s issues. |
125
+ | `searchIssuesPage` | `IssueShape` | Issues matching structured criteria over a repo/org scope — **no** `@me` binding. |
126
+ | `countIssues` | `IssueCountResult` | How many match each scope, fetching none of them. See §5.1. |
127
+ | `getIssuesBatch` | `IssueBatchResult` | Resolves N issues by coordinate or tracker identifier; an absence is proven. |
128
+ | `getPullRequestsBatch` | `PullRequestBatchResult` | Resolves N PRs by `(owner, repo, number)`, in any state; an absence is proven. |
129
+ | `getPullRequestsForBranches` | `PullRequestBranchResult` | Each branch's PRs, in any state and fork-aware; an empty list is a proven none. |
130
+ | `listIssueTrackerIssuesPage` | `IssueShape` | Jira (Cloud + Data Center) / Linear / Trello (issues live under resource → project). |
131
+ | `sweepPullRequests` | `ProviderSweepResult` | Drains **every** page across providers (`maxPages`, default 100). |
132
+ | `sweepClosedPullRequests` | `ProviderSweepResult` | Same, pinned to `['closed','merged']`. |
133
+ | `broadenIssues` | `ProviderBroadenResult` | Per-org fan-out for every visible issue, unfiltered by assignee. |
134
+ | `resolveRepository` | `ResolveRepositoryResult` | Remote URL → canonical provider identity (the `gk repo resolve` equivalent). |
135
+ | `getCurrentAccount` | `CurrentAccountResult` | Who a git host connection is signed in as; trackers refuse. |
136
+ | `getSupportedFilters` | filter capability table | Static, connection-free. See §7. |
135
137
 
136
138
  A provider that cannot serve a surface says so explicitly — a warning explaining that the operation is
137
139
  unsupported plus `fetchFailed`, never a silent empty page. That distinction is the whole point of the result
138
140
  shape: an empty `items` with no warning means "this account genuinely has nothing".
139
141
 
140
- `getTrackerIssue` takes `resourceId` for every supported tracker. Jira Cloud also takes `resourceUrl`, the site URL
141
- returned by `listOrgs`; the REST response only supplies an API `self` link, so the caller provides the already-known
142
- site identity rather than making this point read perform resource discovery. Linear does not need it, and neither
143
- does Jira Data Center, whose browser link is built from the connection's own base URL.
144
-
145
- For Jira Data Center `resourceId` is the host — the instance's single resource, as `listOrgs` reports it — and the
146
- read takes the `domain` its siblings take to select the instance. Unlike them it never falls back to the primary
147
- connection: a self-managed tracker requires a `domain` or a `connectionId` with a configured host, and is refused
148
- (warning + `fetchFailed`) otherwise. Two self-hosted instances routinely share project and issue keys, and this
149
- read's `issue: undefined` is a proven absence a caller may cache, so an answer from whichever host happens to be
150
- primary would be cached under a key that names a different instance. For the same reason a `resourceId` that names
151
- a different host than the one the read resolves to is refused rather than read.
142
+ `getIssuesBatch` takes the target form its provider addresses an issue by: `{ key, owner, repo, number, project? }` on
143
+ GitHub/GHE, GitLab and Azure DevOps, and `{ key, resourceId, resourceUrl?, identifier }` on Jira (Cloud and Data
144
+ Center) and Linear; a call carrying the other form is refused whole. GitHub/GHE resolve up to 25 coordinates per
145
+ request; GitLab, Azure DevOps and the trackers cost one request per target. Azure DevOps requires `project` and
146
+ ignores `repo`, since work items belong to the project. Rows take the repository-scoped `listIssuesPage` conversion,
147
+ except that an Azure DevOps row has no `project`, which only the account-wide read fills from project discovery. What
148
+ counts as a proven absence is per host. On GitLab it is a null project or issue, and a miss costs a second request to
149
+ confirm it, since provider-apis reports a reply carrying only GraphQL errors the same way; a 404 or an empty response
150
+ fails the target. On Azure DevOps it is Azure's own 404 body naming the work item (`WorkItemUnauthorizedAccessException`,
151
+ which Azure also uses for a work item this connection cannot read) or the project
152
+ (`ProjectDoesNotExistWithNameException`); an HTML 404, a 410 or any other `typeKey` fails the target. Bitbucket and
153
+ Bitbucket DC have no issues and refuse. A tracker target's `resourceId` is trusted, so the read performs no resource
154
+ discovery. Jira Cloud also requires `resourceUrl`, the site URL returned by `listOrgs`; the REST response only supplies
155
+ an API `self` link, so the caller provides the already-known site identity. Linear does not need it, and neither does
156
+ Jira Data Center, whose browser link is built from the connection's own base URL. A key asked of several resources is
157
+ one call, with one target per resource.
158
+
159
+ For Jira Data Center a target's `resourceId` is the host — the instance's single resource, as `listOrgs` reports it —
160
+ and the call takes the `domain` its siblings take to select the instance. Unlike them it never falls back to the
161
+ primary connection: a self-managed tracker requires a `domain` or a `connectionId` with a configured host, and the
162
+ whole call is refused (warning + `fetchFailed`) otherwise. Two self-hosted instances routinely share project and
163
+ issue keys, and this read's `issue: undefined` is a proven absence a caller may cache, so an answer from whichever
164
+ host happens to be primary would be cached under a key that names a different instance. For the same reason, a call
165
+ in which any target's `resourceId` names a different host than the one the read resolves to is refused whole rather
166
+ than read.
167
+
168
+ `getPullRequestsBatch` is the pull request counterpart of `getIssuesBatch`, with the same absence/failure contract,
169
+ and it serves every git host. Azure DevOps also requires `project` on each target. GitHub/GHE resolve up to 25
170
+ targets per request; every other host costs one request per target, and GitLab a second one to confirm a miss. A
171
+ target GitHub refuses on its own, e.g. in an org enforcing SAML SSO the token isn't authorized for, fails only that
172
+ target. Its rows carry the same fields as the list reads' rows, except on Bitbucket Cloud — which has no single pull
173
+ request read in provider-apis, so those rows come from GitLens' own REST read and lack `commentsCount`, `isDraft`
174
+ and the clone URLs. On GitLab, a miss the confirming read then contradicts fails the target rather than answering
175
+ with the confirming read's own, differently-identified row. It is uncached and bypasses the
176
+ host's `IntegrationCacheProvider.getPullRequest`, so the caller owns caching the answer.
177
+
178
+ `getPullRequestsForBranches` answers "which pull requests have this branch as their head" without the user's
179
+ relationship to them, so unlike the sweeps it finds a teammate's pull request from the user's branch. A target names
180
+ the repository the pull requests are opened against, the branch's short name and, for a branch in a fork,
181
+ `headOwner`; one equal to the target's owner means the base repository. A pull request matches only when its head
182
+ repository is that base repository or that fork, so a `main` never claims every fork's `main`. The match is on the
183
+ head branch name in every state, so a merged pull request whose branch was deleted is still found. Each target
184
+ returns up to 10, most recently updated first. An empty list without `truncated` is a proven none, a missing base
185
+ repository included; `truncated` means more may match than were returned. GitHub/GHE answer up to 25 targets per
186
+ request, and every other host costs one request per target. GitLab and Azure DevOps, where that request only finds
187
+ the matching numbers, then resolve each match (typically 0–1 per branch) through `getPullRequestsBatch`'s own read,
188
+ so their rows are exactly its rows; a match that read can't check fails its whole branch. Rows carry the list reads'
189
+ fields on GitHub/GHE and Bitbucket DC and the by-id read's on Bitbucket Cloud. Bitbucket DC and Azure DevOps refuse a
190
+ `headOwner` naming another owner, since neither can find a fork by its owner. It is uncached and bypasses
191
+ `IntegrationCacheProvider.getPullRequestForBranch`.
192
+
193
+ `getCurrentAccount` answers who a git host connection is signed in as. It returns a single `account?` rather
194
+ than `items`, and `account` is never absent without a warning: no session, a failed request, or an issue tracker,
195
+ which has only a per-resource account and refuses (see §8). It goes through the host-supplied
196
+ `IntegrationManagerCacheProvider.getCurrentAccount` cache rather than adding a second one.
152
197
 
153
198
  ## 5. Paging
154
199
 
@@ -396,14 +441,17 @@ how far it reaches. **Its absence means account-wide or unattributed**, so a con
396
441
  keeps its existing behavior. It is set only on warnings derived from a structured scope failure, and names at
397
442
  least one ID when present; a failure attributed to nothing below the provider carries none. A warning built
398
443
  from a caught exception never carries one, even when that call targeted a single organization, and an omission
399
- keeps its attribution in `omission.scope` instead.
444
+ keeps its attribution in `omission.scope` instead. The batch reads (`getIssuesBatch`, `getPullRequestsBatch`,
445
+ `getPullRequestsForBranches`) are the exception: a refused target's warning names the scope its target names —
446
+ the Azure DevOps organization and project, the repository on other git hosts, or the tracker's resource.
400
447
 
401
448
  A scoped `auth` failure also means **the credential itself was accepted**. A dead token can come back as
402
449
  nothing but scoped refusals wherever a read reaches its scopes without an uncached request to the connection
403
450
  first: discovery served from a per-token cache (Azure DevOps, Bitbucket and Jira Cloud cache the account, its
404
451
  organizations, workspaces or sites, and their projects), or an SDK fan-out across the requested repositories
405
452
  (Bitbucket Data Center). So when a read's only auth failures are scoped, those providers confirm the credential
406
- with one uncached check before reporting them. A refused credential fails the whole read instead: an
453
+ with one uncached check before reporting them; a batch read does so only when every target was refused, since a
454
+ target that answered already proved the credential. A refused credential fails the whole read instead: an
407
455
  unscoped `auth` warning, `fetchFailed`, no results served from the cache, and the usual connection recovery.
408
456
  A refusal the provider pins on the credential itself, like Bitbucket's or Jira Cloud's for a token missing the
409
457
  OAuth scopes the read needs, is published unscoped too, once for the connection, because a reconnect
@@ -669,12 +717,14 @@ Derived from the provider models and `providersMetadata`. ✓ supported · ✗ r
669
717
  | Issues, account-wide | ✓ | ✓ | ✗ | ✗ | ✓ | — | — | — |
670
718
  | `searchIssuesPage` | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
671
719
  | `countIssues` | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
672
- | `getIssuesBatch` | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
673
- | `getTrackerIssue` | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✓ | ✗ |
720
+ | `getIssuesBatch` | ✓ | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | ✗ |
721
+ | `getPullRequestsBatch` | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
722
+ | `getPullRequestsForBranches` | ✓ | ✓ | ✓ | ✓¹ | ✓¹ | ✗ | ✗ | ✗ |
674
723
  | Issues by `org`/`project` | ✗ | ✗ | ✗ | ✗ | ✓ | ✓ | ✓ | ✓ |
675
724
  | `listIssueTrackerIssuesPage` | — | — | — | — | — | ✓ | ✓ | ✓ |
676
725
  | `broadenIssues` | ✓ | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ |
677
726
  | `resolveRepository` | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
727
+ | `getCurrentAccount` | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
678
728
 
679
729
  Bitbucket Data Center exposes its projects through `listOrgs`: both `id` and `name` are the project key.
680
730
  Pass that key as `org` to `listRepos` to select a project, or omit `org` to enumerate all accessible repositories,
@@ -687,11 +737,15 @@ HTTPS links are rebuilt from the configured URL and an SSH link, whose host and
687
737
 
688
738
  Jira Data Center inherits Jira Cloud's row. Its reads are addressed per host, so `domain` selects the instance and
689
739
  every read below is scoped to that one connection; a paged read that omits it gets the primary configured host,
690
- while `getTrackerIssue` refuses instead (see §4). `listOrgs` returns exactly one resource — the
740
+ while `getIssuesBatch` refuses instead (see §4). `listOrgs` returns exactly one resource — the
691
741
  instance itself, synthesized from the configured host rather than fetched — and its projects carry the display name
692
742
  as `key`, because `/rest/api/2/project` reports no project key; reads address the project by id regardless. No
693
743
  autolinks are registered for the same reason: an autolink prefix has to be the project key.
694
744
 
745
+ ¹ Branches in the base repository only: a target whose `headOwner` names another owner is refused, since Bitbucket DC
746
+ finds a branch's pull requests only through the repository the branch lives in, and an Azure DevOps fork shares its
747
+ organization.
748
+
695
749
  Repo-scoped PR filters: GitHub/GHE `Author, Assignee, ReviewRequested, Mention` · GitLab `Author, Assignee,
696
750
  ReviewRequested` · Bitbucket + Bitbucket DC `Author, ReviewRequested` · Azure `Author, Assignee,
697
751
  ReviewRequested`.