agentHostGitService.ts ×59

Frontier kind: Joint frontier

unlabeled · c_b02a93e96399

45 tests · 18013 LOC · 61 files · introduces 1 test · 259 LOC · 1 file

Introduces — evidence that enters the hierarchy at this concept

Code
59 ranges259 lines · 1 files
Tests
1 test

Contains — complete concept membership

All code (extent)
1753 ranges18013 lines · 61 files · Browse complete extent
All tests (intent)
45 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

1 test introduced at this concept.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

1 file ranked by introduced lines: 259 introduced LOC across 59 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/agentHost/node/agentHostGitService.ts 259 introduced LOC · 59 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- agentHostGitService.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import * as cp from 'child_process';
7 > import * as fsPromises from 'fs/promises';
8 > import { cp as copyFile } from '@vscode/fs-copyfile';
9 > import * as path from '../../../base/common/path.js';
10 > import { URI } from '../../../base/common/uri.js';
11 > import { VSBuffer } from '../../../base/common/buffer.js';
12 > import { parse } from '../../../base/common/glob.js';
13 > import { generateUuid } from '../../../base/common/uuid.js';
14 > import { INativeEnvironmentService } from '../../environment/common/environment.js';
15 > import { IFileService } from '../../files/common/files.js';
16 > import { ILogService } from '../../log/common/log.js';
17 > import { FileEditKind, type ISessionFileDiff, type ISessionGitState } from '../common/state/sessionState.js';
18 > import { buildGitBlobUri } from './gitDiffContent.js';
19 > import { EMPTY_TREE_OBJECT, IAgentHostGitService, IBranch, IBranchDiffSafetyInfo, IRefQuery, IComputeSessionFileDiffsOptions, IDefaultBranch, IPullOptions, IPushOptions, GitRefType, IRemoteBranch, GitRef, ITag, Branch } from '../common/agentHostGitService.js';
20 > import { LRUCache } from '../../../base/common/map.js';
21 > import { Limiter, SequencerByKey } from '../../../base/common/async.js';
22 >
23 > export class AgentHostGitService implements IAgentHostGitService {
24 > declare readonly _serviceBrand: undefined;
25 >
26 > /**
27 > * A cache of repository roots that have already been discovered.
28 > */
29 > private readonly _repositoryRoots = new LRUCache<string, URI>(100);
30 > private readonly _repositoryRootSequencer = new SequencerByKey<string>();
31 >
32 > constructor(
33 @IFileService private readonly _fileService: IFileService,
34 @INativeEnvironmentService private readonly _environmentService: INativeEnvironmentService,
35 @ILogService private readonly _logService: ILogService,
36 ) { }
38 > async getCurrentBranch(workingDirectory: URI): Promise<string | undefined> {
39 return (await this._runGit(workingDirectory, ['branch', '--show-current']))?.trim()
40 || (await this._runGit(workingDirectory, ['rev-parse', '--short', 'HEAD']))?.trim()
41 || undefined;
42 }
44 > async getDefaultBranch(workingDirectory: URI): Promise<IDefaultBranch | undefined> {
45 // Try to read the default branch from the remote HEAD reference
46 const remoteRef = (await this._runGit(workingDirectory, ['symbolic-ref', 'refs/remotes/origin/HEAD']))?.trim();
67 return undefined;
68 }
70 > async getRefs(workingDirectory: URI, query?: IRefQuery): Promise<GitRef[]> {
71 const args = ['for-each-ref', '--format=%(refname)%00%(upstream)'];
72
89 return parseGitRefs(output);
90 }
92 > async getBranches(workingDirectory: URI, query?: IRefQuery): Promise<Branch[]> {
93 const refs = await this.getRefs(workingDirectory, query);
94 return refs.filter(r => r.kind === GitRefType.Head || r.kind === GitRefType.RemoteHead);
95 }
97 > async getBranch(workingDirectory: URI, name: string): Promise<Branch | undefined> {
98 const refs = await this.getBranches(workingDirectory, { pattern: name });
99 return refs.length > 0 ? refs[0] : undefined;
100 }
102 > async getRepositoryRoot(workingDirectory: URI): Promise<URI | undefined> {
103 const workingDirectoryKey = workingDirectory.toString();
104
122 });
123 }
125 > async getWorktreeRoots(workingDirectory: URI): Promise<URI[]> {
126 const output = await this._runGit(workingDirectory, ['worktree', 'list', '--porcelain']);
127 if (!output) {
132 .map(line => URI.file(line.substring('worktree '.length)));
133 }
135 > async addWorktree(repositoryRoot: URI, worktree: URI, branchName: string, startPoint: string): Promise<void> {
136 const resolvedStartPoint = await this._resolveRemoteTrackingBranch(repositoryRoot, startPoint) ?? startPoint;
137 // Pass --no-track so the new agent branch never picks up upstream
141 await this._runGit(repositoryRoot, ['-c', 'checkout.workers=0', 'worktree', 'add', '--no-track', '-b', branchName, worktree.fsPath, resolvedStartPoint], { timeout: 180_000, throwOnError: true });
142 }
144 > async copyWorktreeIncludeFiles(repositoryRoot: URI, worktree: URI, globs: readonly string[]): Promise<void> {
145 try {
146 const worktreeIncludePaths = await this._getWorktreeIncludePaths(repositoryRoot, globs);
170 }
171 }
173 > async addExistingWorktree(repositoryRoot: URI, worktree: URI, branchName: string): Promise<void> {
174 // `-f` (force) so recreation succeeds even when the worktree directory was
175 // deleted out-of-band but git still has it registered ("missing but
178 await this._runGit(repositoryRoot, ['-c', 'checkout.workers=0', 'worktree', 'add', '-f', worktree.fsPath, branchName], { timeout: 180_000, throwOnError: true });
179 }
181 > async removeWorktree(repositoryRoot: URI, worktree: URI): Promise<void> {
182 await this._runGit(repositoryRoot, ['worktree', 'remove', '--force', worktree.fsPath], { timeout: 60_000, throwOnError: true });
183 }
185 > async branchExists(repositoryRoot: URI, branchName: string): Promise<boolean> {
186 // `show-ref --verify --quiet` exits 0 when the ref exists and 1 otherwise.
187 // `_runGit` returns undefined on non-zero exit, so `!== undefined` is the existence signal.
189 return output !== undefined;
190 }
192 > async hasUncommittedChanges(workingDirectory: URI): Promise<boolean> {
193 const output = await this._runGit(workingDirectory, ['status', '--porcelain']);
194 return !!output && output.trim().length > 0;
195 }
197 > async commitAll(workingDirectory: URI, message: string): Promise<void> {
198 await this._runGit(workingDirectory, ['add', '-A', '--', ':/'], { throwOnError: true });
199 await this._runGit(workingDirectory, ['commit', '--no-verify', '-m', message], { timeout: 60_000, throwOnError: true });
200 }
202 > async restore(workingDirectory: URI, paths: readonly string[], options?: { readonly staged?: boolean; readonly ref?: string }): Promise<void> {
203 const args = ['restore'];
204
217 await this._runGit(workingDirectory, [...args, '--', ...paths], { throwOnError: true });
218 }
220 > async hasUpstream(workingDirectory: URI, branchName: string): Promise<boolean> {
221 const output = await this._runGit(workingDirectory, ['rev-parse', '--abbrev-ref', `${branchName}@{upstream}`]);
222 return output !== undefined && output.trim().length > 0;
223 }
225 > async pull(workingDirectory: URI, options?: IPullOptions): Promise<void> {
226 const args = ['pull'];
227
243 await this._runGit(workingDirectory, args, { timeout: 180_000, throwOnError: true });
244 }
246 > async push(workingDirectory: URI, options?: IPushOptions): Promise<void> {
247 const args = ['push'];
248
264 await this._runGit(workingDirectory, args, { timeout: 180_000, throwOnError: true });
265 }
267 > async computeSessionFileDiffs(workingDirectory: URI, options: IComputeSessionFileDiffsOptions): Promise<readonly ISessionFileDiff[] | undefined> {
268 // All git invocations run from the working tree's repository root so
269 // `--raw` paths are repo-relative — that's what `git show <sha>:<path>`
301 return parseGitDiffRawNumstat(rawDiffOutput, repositoryRoot, options.sessionUri, mergeBaseCommit);
302 }
304 > async resolveBranchBaselineCommit(workingDirectory: URI, baseBranch?: string): Promise<string | undefined> {
305 const repositoryRoot = await this.getRepositoryRoot(workingDirectory);
306 if (!repositoryRoot) {
310 return this._resolveBranchMergeBaseCommit(repositoryRoot, baseBranch);
311 }
313 > /**
314 > * Resolves the merge-base commit-ish the Branch Changes baseline is anchored
315 > * on. With a base branch, prefers the corresponding `origin/<base>`
316 > * remote-tracking ref when it exists so branch changes match a PR-style
317 > * comparison even if the local base branch is stale. Without a usable base,
318 > * falls back to `HEAD` (surfaces uncommitted work but no committed-on-branch
319 > * work). For empty repos with no `HEAD`, falls back to the empty-tree object.
320 > * Always resolves to a commit-ish (never `undefined`) once the repository
321 > * root is known.
322 > */
323 > private async _resolveBranchMergeBaseCommit(repositoryRoot: URI, baseBranch?: string): Promise<string> {
324 let mergeBaseCommit: string | undefined;
325 if (baseBranch) {
333 return mergeBaseCommit ?? EMPTY_TREE_OBJECT;
334 }
336 > private async _runWithTempIndex(repositoryRoot: URI, mergeBaseCommit: string, changedPaths: readonly string[]): Promise<string | undefined> {
337 // Build a throwaway index so we can stage the changed working tree
338 // paths (including untracked files) without disturbing the user's real
364 }
365 }
367 > private async _stageChangedPaths(repositoryRoot: URI, tempDir: URI, changedPaths: readonly string[], env: Record<string, string>): Promise<boolean> {
368 if (changedPaths.length === 0) {
369 return true;
381 }) !== undefined;
382 }
384 > private async _resolveRemoteTrackingBranch(repositoryRoot: URI, branch: string): Promise<string | undefined> {
385 const remoteBranch = `origin/${branch}`;
386 const output = await this._runGit(repositoryRoot, ['show-ref', '--verify', '--quiet', `refs/remotes/${remoteBranch}`]);
387 return output !== undefined ? remoteBranch : undefined;
388 }
390 > private async _getWorktreeIncludePaths(repositoryRoot: URI, globs: readonly string[]): Promise<string[]> {
391 if (globs.length === 0) {
392 return [];
478 return includePaths.map(entry => path.join(repositoryRoot.fsPath, entry));
479 }
481 > async showBlob(workingDirectory: URI, ref: string, repoRelativePath: string): Promise<VSBuffer | undefined> {
482 const repositoryRoot = await this.getRepositoryRoot(workingDirectory);
483 if (!repositoryRoot) {
498 });
499 }
501 > async getSessionGitState(workingDirectory: URI): Promise<ISessionGitState | undefined> {
502 return this._computeSessionGitState(workingDirectory);
503 }
505 > async getFetchRemoteUrls(workingDirectory: URI, preferredRemote?: string): Promise<readonly string[] | undefined> {
506 const repositoryRoot = await this.getRepositoryRoot(workingDirectory);
507 if (!repositoryRoot) {
510 return parseFetchRemoteUrls(await this._runGit(repositoryRoot, ['remote', '-v']), preferredRemote);
511 }
513 > async getUntrackedPaths(workingDirectory: URI): Promise<readonly string[] | undefined> {
514 const repositoryRoot = await this.getRepositoryRoot(workingDirectory);
515 if (!repositoryRoot) {
519 return status === undefined ? undefined : parseUntrackedPaths(status);
520 }
522 > async captureWorkingTreeAsTree(workingDirectory: URI): Promise<string | undefined> {
523 const repositoryRoot = await this.getRepositoryRoot(workingDirectory);
524 if (!repositoryRoot) {
550 }
551 }
553 > async commitTree(repositoryRoot: URI, treeOid: string, parentOid: string | undefined, message: string): Promise<string | undefined> {
554 const args = ['commit-tree', treeOid];
555 if (parentOid) {
560 return out?.trim() || undefined;
561 }
563 > async updateRef(repositoryRoot: URI, ref: string, newOid: string): Promise<void> {
564 await this._runGit(repositoryRoot, ['update-ref', ref, newOid], { throwOnError: true });
565 }
567 > async deleteRefs(repositoryRoot: URI, refs: readonly string[]): Promise<void> {
568 if (refs.length === 0) {
569 return;
581 });
582 }
584 > async revParse(repositoryRoot: URI, expression: string): Promise<string | undefined> {
585 const out = await this._runGit(repositoryRoot, ['rev-parse', '--verify', '--quiet', expression]);
586 return out?.trim() || undefined;
587 }
589 > async overlayPathIntoTree(repositoryRoot: URI, baseTreeOid: string, path: string, sourceTreeOid: string): Promise<string | undefined> {
590 // Build a throwaway index seeded from `baseTreeOid`, replace/remove the
591 // single `path` using `sourceTreeOid`, and write the result back out as
630 }
631 }
633 > async diffTreePaths(repositoryRoot: URI, fromTreeish: string, toTreeish: string): Promise<string[] | undefined> {
634 const out = await this._runGit(repositoryRoot, ['diff', '--name-only', '--no-renames', '-z', fromTreeish, toTreeish, '--']);
635 if (out === undefined) {
638 return out.split('\x00').filter(Boolean);
639 }
641 > async computeFileDiffsBetweenRefs(workingDirectory: URI, options: { readonly sessionUri: string; readonly fromRef: string; readonly toRef: string }): Promise<readonly ISessionFileDiff[] | undefined> {
642 const repositoryRoot = await this.getRepositoryRoot(workingDirectory);
643 if (!repositoryRoot) {
657 }
658 }
660 > async getBranchDiffSafetyInfo(workingDirectory: URI, baselineCommit: string): Promise<IBranchDiffSafetyInfo | undefined> {
661 const repositoryRoot = await this.getRepositoryRoot(workingDirectory);
662 if (!repositoryRoot) {
681 };
682 }
684 > async getDiffPatchBetweenRefs(workingDirectory: URI, options: { readonly fromRef: string; readonly toRef: string; readonly paths: readonly string[]; readonly maxBuffer: number }): Promise<{ readonly patch: string | undefined; readonly tooLarge: boolean } | undefined> {
685 const repositoryRoot = await this.getRepositoryRoot(workingDirectory);
686 if (!repositoryRoot) {
701 }
702 }
704 > private async _computeSessionGitState(workingDirectory: URI): Promise<ISessionGitState | undefined> {
705 const repositoryRoot = await this.getRepositoryRoot(workingDirectory);
706 if (!repositoryRoot) {
756 return stripUndefined(result);
757 }
759 > private _runGit(workingDirectory: URI, args: readonly string[], options?: { readonly timeout?: number; readonly throwOnError?: boolean; readonly env?: Record<string, string>; readonly maxBuffer?: number }): Promise<string | undefined> {
760 this._logService.trace(`[agentHostGitService] > git ${args.join(' ')}`);
761
795 });
796 }
798 >
799 > /**
800 > * Returns the shallowest directory from `directories` that contains `file`, or
801 > * `undefined` if none does. `file` is a repository-relative, forward-slash path
802 > * and every entry in `directories` is expected to end with a trailing `/` (as
803 > * produced by `git ls-files --directory`). Walking the path's `/` boundaries
804 > * and probing the set is O(path depth) per file, avoiding an O(directories)
805 > * scan for each file.
806 > */
807 function findContainingDirectory(file: string, directories: ReadonlySet<string>): string | undefined {
808 let index = file.indexOf('/');
816 return undefined;
817 }
819 > /**
820 > * Builds a diagnostic error message for a failed `git` invocation that
821 > * preserves the reason (timeout / signal / exit code) instead of just
822 > * surfacing whatever happened to be on stderr. When `git` is killed by
823 > * the timeout, stderr often contains only progress output (e.g.
824 > * `Updating files: 0% (149/14834)`), so without the timeout indicator
825 > * the bubbled-up error is misleading.
826 > *
827 > * Exported for tests.
828 > */
829 > export function formatGitError(args: readonly string[], timeoutMs: number, didTimeOut: boolean, error: cp.ExecFileException, stderr: string): string {
830 const subcommand = args[0] ?? '(unknown)';
831 let reason: string;
842 return detail ? `${reason}: ${detail}` : reason;
843 }
845 > /**
846 > * Squashes multi-line / carriage-return-heavy stderr (e.g. git progress
847 > * meters that emit `Updating files: 0% (149/14834)\r...` repeatedly)
848 > * into a single short line suitable for a one-liner error message.
849 > * Keeps the most recent non-empty line and caps total length.
850 > *
851 > * Exported for tests.
852 > */
853 > export function summarizeStderrForError(stderr: string): string {
854 if (!stderr) {
855 return '';
867 return summary.length > MAX ? `${summary.slice(0, MAX - 1)}…` : summary;
868 }
870 > /**
871 > * Parses NUL-separated `git status --porcelain=v1 -z --untracked-files=all`
872 > * output and returns the repo-relative paths of untracked entries (status
873 > * `??`). Other entries are ignored; we only need to know whether any
874 > * untracked files exist to decide whether to use the temp-index path.
875 > *
876 > * Exported for tests.
877 > */
878 > export function parseUntrackedPaths(output: string | undefined): string[] {
879 return parseChangedPaths(output, status => status === '??');
880 }
882 > /**
883 > * Parses NUL-separated `git status --porcelain=v1 -z --untracked-files=all`
884 > * output and returns all changed repo-relative paths. Rename/copy entries
885 > * include both the destination and source paths so scoped `git add -A`
886 > * stages both sides of the change.
887 > *
888 > * Exported for tests.
889 > */
890 > export function parseChangedPaths(output: string | undefined, includeStatus: (status: string) => boolean = () => true): string[] {
891 if (!output) {
892 return [];
923 return result;
924 }
926 > /**
927 > * Parses NUL-terminated `git ls-tree -z <tree> -- <path>` output for a single
928 > * path and returns its `{ mode, oid }`, or `undefined` when the path is absent
929 > * from the tree (empty output). Each entry has the form
930 > * `<mode> SP <type> SP <oid> TAB <path> NUL`; we only need the mode and oid.
931 > *
932 > * Exported for tests.
933 > */
934 > export function parseSingleLsTreeEntry(output: string | undefined): { mode: string; oid: string } | undefined {
935 if (!output) {
936 return undefined;
947 return { mode: meta[0], oid: meta[2] };
948 }
950 > /**
951 > * Parses combined `--raw --numstat -z` output produced by
952 > * {@link IAgentHostGitService.computeSessionFileDiffs} and converts each
953 > * change into an {@link ISessionFileDiff} ready for the protocol.
954 > *
955 > * The combined NUL-separated stream alternates between `--raw` segments
956 > * (start with `:`) and `--numstat` segments. For renames the raw segment
957 > * is followed by two extra path segments (old, new); the numstat segment
958 > * has an empty path field followed by old/new path segments.
959 > *
960 > * `beforeRef` is the commit the `before` side is anchored on (typically a
961 > * merge-base or the lower bound of a ref-to-ref diff).
962 > *
963 > * `afterRef` controls how the `after` side is built:
964 > * - When `undefined` (the merge-base → working-tree case) the `after`
965 > * content URI points at the on-disk working-tree file. The diff editor
966 > * reads the file from disk as the user currently sees it.
967 > * - When set (the ref → ref case, e.g. checkpoint diffs) both `after.uri`
968 > * and `after.content.uri` are built as `git-blob:` URIs anchored on that
969 > * commit, so the after pane reflects the state at that commit
970 > * regardless of what is currently on disk. This also makes the diff
971 > * correct when the file does not (or no longer) exists in the working
972 > * tree.
973 > *
974 > * Exported for tests.
975 > */
976 > export function parseGitDiffRawNumstat(output: string, repositoryRoot: URI, sessionUri: string, beforeRef: string, afterRef?: string): ISessionFileDiff[] {
977 const segments = output.split('\x00');
978 const changes: { kind: FileEditKind; oldPath?: string; newPath?: string }[] = [];
1065 });
1066 }
1068 > /**
1069 > * Parses output of `git status -b --porcelain=v2`. The format is documented
1070 > * at https://git-scm.com/docs/git-status. We care about a few header lines:
1071 > *
1072 > * # branch.head <name>
1073 > * # branch.upstream <name>
1074 > * # branch.ab +<ahead> -<behind>
1075 > *
1076 > * and the count of non-header lines (one per changed entry).
1077 > *
1078 > * Exported for tests.
1079 > */
1080 > export function parseGitStatusV2(output: string | undefined): {
1081 branchName?: string;
1082 upstreamBranchName?: string;
1114 return { branchName, upstreamBranchName, outgoingChanges, incomingChanges, uncommittedChanges };
1115 }
1117 > /** Exported for tests. */
1118 > export function parseHasGitHubRemote(remotesOutput: string | undefined): boolean | undefined {
1119 if (remotesOutput === undefined) {
1120 return undefined;
1125 return /github\.com[:\/]/i.test(remotesOutput);
1126 }
1128 > /** Returns fetch remote URLs with the preferred remote, then `origin`, first. */
1129 > export function parseFetchRemoteUrls(remotesOutput: string | undefined, preferredRemote?: string): string[] | undefined {
1130 if (remotesOutput === undefined) {
1131 return undefined;
1146 return [...new Set(ordered.map(candidate => candidate.url))];
1147 }
1149 > /**
1150 > * Parse `owner` and `repo` from `git remote -v` output. Prefers the `origin`
1151 > * remote; falls back to the first GitHub remote so worktrees that renamed
1152 > * the remote still surface PR state. Returns `undefined` if no GitHub
1153 > * remote is present or the URL doesn't match a GitHub repo shape.
1154 > *
1155 > * Exported for tests.
1156 > */
1157 > export function parseGitHubRepoFromRemote(remotesOutput: string | undefined): { owner: string; repo: string } | undefined {
1158 const candidates = parseFetchRemoteUrls(remotesOutput);
1159 if (!candidates) {
1168 return undefined;
1169 }
1171 > /**
1172 > * Extract `{owner, repo}` from a GitHub remote URL. Handles the common
1173 > * forms: `[email protected]:owner/repo(.git)?`, `https://github.com/owner/repo(.git)?`,
1174 > * `ssh://[email protected]/owner/repo(.git)?`, `git://github.com/owner/repo(.git)?`.
1175 > */
1176 function parseGitHubOwnerRepoFromUrl(url: string): { owner: string; repo: string } | undefined {
1177 // SCP-like: [email protected]:owner/repo(.git)?
1187 return undefined;
1188 }
1190 > /** Exported for tests. */
1191 > export function parseDefaultBranchRef(symbolicRefOutput: string | undefined): string | undefined {
1192 const ref = symbolicRefOutput?.trim();
1193 if (!ref) { return undefined; }
1195 return ref.startsWith(prefix) ? ref.substring(prefix.length) : ref;
1196 }
1198 > export function parseRemoteBranchRef(ref: string): { ref: string; name: string; remote: string } | undefined {
1199 if (!ref.startsWith('refs/remotes/')) {
1200 return undefined;
1205 return { ref, name, remote };
1206 }
1208 > export function parseGitRefs(output: string | undefined): GitRef[] {
1209 if (!output) {
1210 return [];
1243 return refs;
1244 }
1246 function stripUndefined<T extends object>(obj: T): T {
1247 const out: Record<string, unknown> = {};
1251 return out as T;
1252 }
1254 function isMaxBufferError(error: unknown): boolean {
1255 const cause = error instanceof Error ? error.cause : undefined;