Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
d2d5bba
feat(web): pull request files can be marked as viewed
yordis Aug 20, 2026
cf5ac4c
fix(server): an overpriced write guess no longer pauses reads until t…
yordis Aug 20, 2026
e62d906
fix(web): a failed press no longer takes back a tick the reader made …
yordis Aug 20, 2026
19a679c
fix(web): a viewed tick redraws its file, and a partial count says th…
yordis Aug 20, 2026
447fd19
style: plainer punctuation in the viewed files comments
yordis Aug 20, 2026
d085d08
fix(web): pressing the word beside the box no longer folds the file t…
yordis Aug 20, 2026
4891bcd
fix(server): a write no longer guesses at a budget only the host can …
yordis Aug 20, 2026
dad689d
fix(web): a failed request no longer answers for a press a later one …
yordis Aug 20, 2026
9628643
fix(web): a viewed tick no longer rebuilds every header on screen
yordis Aug 20, 2026
6b44e51
fix(web): the viewed box says what it is for out loud
yordis Aug 20, 2026
28eea17
Merge upstream main into yordis/feat-pr-files-viewed-upstream
yordis Aug 27, 2026
aa7a828
fix(web): a refreshed review re-asks for the ticks
yordis Aug 28, 2026
5f08047
fix(web): a superseded write no longer reports a failure
yordis Aug 28, 2026
3c279bf
fix(web): a dropped connection no longer reports a rejected write
yordis Aug 28, 2026
f5c7f62
feat(server): GitLab reviewers can keep their place in a long merge r…
yordis Aug 30, 2026
53253a2
fix(web): a GitLab reader can tell whose viewed marks these are
yordis Aug 30, 2026
1de680d
fix(web): Azure DevOps pull request links open in the app
yordis Aug 30, 2026
0876415
feat(server): Bitbucket reviewers keep their place in a long review
yordis Aug 30, 2026
9146a44
feat(server): Azure DevOps pull requests show their files
yordis Aug 30, 2026
bbf04bb
perf(server): a review's ticks stop waiting on the host
yordis Aug 30, 2026
cd7cccc
fix(server): a long or unreadable Azure change still renders its diff
yordis Aug 30, 2026
75c0bb8
fix(server): a review's ticks survive what the host could not read
yordis Aug 30, 2026
a95bf64
fix(server): a part-read Azure change no longer passes as the whole o…
yordis Aug 30, 2026
644839c
fix(server): a diff given up on no longer costs the whole slice again…
yordis Aug 30, 2026
b060805
fix(server): a rate-limited Azure diff no longer reads as a change wi…
yordis Aug 31, 2026
6e9d61c
fix(web): the viewed count no longer pushes the code toolbar off the …
yordis Aug 31, 2026
2db1bd7
Merge upstream main into yordis/feat-pr-files-viewed-upstream
yordis Sep 3, 2026
b938067
fix(server): correct viewed-file marks under partial answers and conc…
yordis Sep 3, 2026
d5652e0
Merge upstream main into yordis/feat-pr-files-viewed-upstream
yordis Sep 3, 2026
e8c53a0
fix(server): keep a viewed mark honest when the host answers short
yordis Sep 3, 2026
6639577
fix(server): give a long review's own history room to arrive
yordis Sep 3, 2026
f21e8ee
Merge upstream main into yordis/feat-pr-files-viewed-upstream
yordis Sep 3, 2026
051fa5a
fix(server): refuse a diff cursor Azure's reader never handed out
yordis Sep 3, 2026
8378409
fix(server): key a GitLab blob by the path the host spelled
yordis Sep 3, 2026
6ec0e31
fix(server): ask Azure for a file by its own spelling of the path
yordis Sep 3, 2026
a1dc7d4
Merge remote-tracking branch 'upstream/main' into yordis/feat-pr-file…
yordis Sep 7, 2026
aeafc27
fix(web): an Azure review's preview and its ticks agree on the reposi…
yordis Sep 7, 2026
ebd14e0
Merge remote-tracking branch 'upstream/main' into yordis/feat-pr-file…
yordis Sep 9, 2026
d622f4e
chore(server): stop exporting helpers only their own module reads
yordis Sep 9, 2026
82d8bb6
docs(web): sentBy guards a repress while a request is out, not overla…
yordis Sep 9, 2026
f4abc08
perf(web): a tick or a fold no longer rehashes every annotation on th…
yordis Sep 9, 2026
413cfc8
fix(web): the viewed checkbox announces the label a reader can see
yordis Sep 9, 2026
814290e
fix(server): a bitbucket path holding a space no longer reads as view…
yordis Sep 9, 2026
47b1409
perf(server): a run of ticks no longer downloads the bitbucket patch …
yordis Sep 9, 2026
99c4662
perf(server): writing to a github pull request no longer re-reads its…
yordis Sep 9, 2026
382eaee
fix(server): a signed-out cli no longer hides the files a reader mark…
yordis Sep 9, 2026
e33e684
fix(server): a workspace refresh re-asks the head what it has of the …
yordis Sep 9, 2026
3ed4814
refactor(server): the pull request service no longer branches on a pr…
yordis Sep 9, 2026
2c471a9
perf(server): an azure change request's files no longer wait on each …
yordis Sep 9, 2026
f4845a6
fix(server): reading an azure diff no longer holds every other client…
yordis Sep 9, 2026
00fa358
docs: pull request comments carry the trap rather than restate the code
yordis Sep 9, 2026
8575b70
docs(server): the gitlab revision doc no longer contradicts the code …
yordis Sep 9, 2026
5712869
docs(server): the revision comments name the layer that turns an abse…
yordis Sep 9, 2026
d08e3f3
refactor(server): the viewed files feature leaves the pull request se…
yordis Sep 9, 2026
71c8572
docs: the null revision rule has one home rather than nine copies tha…
yordis Sep 9, 2026
c65ba1a
docs(server): the bitbucket diff comment matches the punctuation this…
yordis Sep 9, 2026
664237c
chore: merge upstream main into yordis/feat-pr-files-viewed-upstream
yordis Sep 9, 2026
bafd063
fix(server): diff bounds and viewed marks survive slow machines and p…
yordis Sep 9, 2026
39d5e04
Merge remote-tracking branch 'upstream/main' into yordis/feat-pr-file…
yordis Sep 9, 2026
900698c
fix(server): bound how many az processes the whole build has out at once
yordis Sep 9, 2026
7383233
fix(server): bound what one change request can hold and spawn
yordis Sep 10, 2026
cdc24c6
Merge remote-tracking branch 'upstream/main' into yordis/feat-pr-file…
yordis Sep 10, 2026
cf362b8
fix(server): keep what a reader has open out of reach of cold reads
yordis Sep 10, 2026
fac056b
test(server): cover what a live azure organisation answers with
yordis Sep 10, 2026
87aa7cc
fix: keep a viewed mark on the file the host named
yordis Sep 11, 2026
05110fd
Merge remote-tracking branch 'upstream/main' into yordis/feat-pr-file…
yordis Sep 11, 2026
c1a945f
Merge remote-tracking branch 'upstream/main' into yordis/feat-pr-file…
yordis Sep 12, 2026
8addefb
Merge remote-tracking branch 'upstream/main' into yordis/feat-pr-file…
yordis Sep 12, 2026
4c404a8
fix(server): hold background viewer lookups behind a rate-limit pause
yordis Sep 12, 2026
ecaab33
docs(user): say where viewed marks can be made
yordis Sep 12, 2026
5a5b7bd
perf(server): keep the Azure summary read to one process
yordis Sep 12, 2026
e259c2f
refactor(server): cut the review prose out of the new server comments
yordis Sep 12, 2026
63ea078
fix(web): a tick no longer hides a file pushed to since it landed
yordis Sep 12, 2026
9ec8fd4
docs(internals): the revision guide agrees with itself on a failed press
yordis Sep 12, 2026
e92c9f6
test(web): the case where a tick hid a push is guarded through the hook
yordis Sep 12, 2026
8f68fbf
perf(server): stop re-reading a bitbucket pull request's patch on eve…
yordis Sep 12, 2026
69e684d
docs(server): thin out the comments around viewed files
yordis Sep 12, 2026
c98d31b
test(server): pin the viewer lookup a paused host is not asked to repeat
yordis Sep 12, 2026
c835567
Merge remote-tracking branch 'upstream/main' into yordis/feat-pr-file…
yordis Sep 12, 2026
aa11cbc
Merge remote-tracking branch 'upstream/main' into yordis/feat-pr-file…
yordis Sep 14, 2026
0d64740
test(mobile): a cold highlighter is not held to a warm one's tokens
yordis Sep 14, 2026
042e3c6
fix(server): a viewed mark on a wide review stops reporting changes
yordis Sep 14, 2026
0999e68
Merge remote-tracking branch 'upstream/main' into yordis/feat-pr-file…
yordis Sep 16, 2026
e3ce126
revert(mobile): drop the highlighter test rewrite from this branch
yordis Sep 16, 2026
e76dd3a
Merge remote-tracking branch 'upstream/main' into yordis/feat-pr-file…
yordis Sep 16, 2026
ac0da07
fix(web): preserve both imports for main integration
maria-rcks Sep 16, 2026
4695b9a
fix(web): reconcile markdown changes with main
maria-rcks Sep 16, 2026
bcdb951
fix(review): align conflicting files before main integration
maria-rcks Sep 16, 2026
9e6f370
Merge branch 'main' into yordis/feat-pr-files-viewed-upstream
maria-rcks Sep 16, 2026
4dc9155
fix(review): preserve decoded paths after main integration
maria-rcks Sep 16, 2026
b4e5c21
fix(prs): preserve viewed behavior across settings and routed hosts
maria-rcks Sep 16, 2026
f28664a
fix(prs): skip linked sync for viewed-only invalidations
maria-rcks Sep 16, 2026
7534968
fix(prs): integrate main and track Forgejo viewed files
maria-rcks Sep 17, 2026
06c10cd
chore: resolve latest main settings conflicts
maria-rcks Sep 17, 2026
faf2751
Merge branch 'main' into yordis/feat-pr-files-viewed-upstream
maria-rcks Sep 17, 2026
c2b9144
fix(prs): isolate viewed marks by routed repository
maria-rcks Sep 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/server/src/auth/RpcAuthorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const RPC_REQUIRED_SCOPES = {
[WS_METHODS.pullRequestsActivity]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsThreadComments]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsDiffFileContents]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsFilesViewed]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsRunAction]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsUpdate]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsComment]: AuthOrchestrationOperateScope,
Expand All @@ -66,6 +67,7 @@ export const RPC_REQUIRED_SCOPES = {
[WS_METHODS.pullRequestsReplyToThread]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsSetThreadResolution]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsSetReaction]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsSetFilesViewed]: AuthOrchestrationOperateScope,
// Read scope like the reads it un-caches: refreshing is part of reading, and a read-only
// client pressing refresh must not be told it may not look again.
[WS_METHODS.pullRequestsInvalidate]: AuthOrchestrationReadScope,
Expand Down
144 changes: 144 additions & 0 deletions apps/server/src/pullRequest/GitHubPullRequestCli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2603,4 +2603,148 @@ layer("GitHubPullRequestCli.layer", (it) => {
]);
}),
);

it.effect("reads every page of viewed files, and says so when there are too many", () =>
Effect.gen(function* () {
const page = (index: number, hasNextPage: boolean) =>
Effect.succeed(
output(
JSON.stringify({
data: {
repository: {
pullRequest: {
files: {
pageInfo: { hasNextPage, endCursor: `cursor-${index}` },
nodes: [
{ path: `src/file${index}.ts`, viewerViewedState: "VIEWED" },
{ path: `src/other${index}.ts`, viewerViewedState: "UNVIEWED" },
],
},
},
},
},
}),
),
);
mockedExecute
.mockReturnValueOnce(page(0, true))
.mockReturnValueOnce(page(1, true))
.mockReturnValueOnce(page(2, false));
const cli = yield* GitHubPullRequestCli.GitHubPullRequestCli;

const viewed = yield* cli.getPullRequestFilesViewed({
cwd: "/w",
repository: "acme/web",
host: "github.com",
number: 7,
});

assert.strictEqual(mockedExecute.mock.calls.length, 3);
// The first page asks from the start; each one after it carries the cursor before it.
assert.isFalse(callAt(0).args.some((arg) => arg.startsWith("after=")));
expect(callAt(1).args).toContain("after=cursor-0");
expect(callAt(2).args).toContain("after=cursor-1");
assert.isFalse(viewed.truncated);
expect(viewed.files.map((file) => [file.path, file.state])).toEqual([
["src/file0.ts", "viewed"],
["src/other0.ts", "unviewed"],
["src/file1.ts", "viewed"],
["src/other1.ts", "unviewed"],
["src/file2.ts", "viewed"],
["src/other2.ts", "unviewed"],
]);
}),
);

it.effect("stops paging viewed files rather than following a change without end", () =>
Effect.gen(function* () {
mockedExecute.mockReturnValue(
Effect.succeed(
output(
// @effect-diagnostics-next-line preferSchemaOverJson:off
JSON.stringify({
data: {
repository: {
pullRequest: {
files: {
pageInfo: { hasNextPage: true, endCursor: "cursor" },
nodes: [{ path: "src/file.ts", viewerViewedState: "VIEWED" }],
},
},
},
},
}),
),
),
);
const cli = yield* GitHubPullRequestCli.GitHubPullRequestCli;

const viewed = yield* cli.getPullRequestFilesViewed({
cwd: "/w",
repository: "acme/web",
host: "github.com",
number: 7,
});

assert.strictEqual(mockedExecute.mock.calls.length, 5);
assert.isTrue(viewed.truncated);
assert.strictEqual(viewed.files.length, 5);
}),
);

it.effect("clears and restores a burst of files in one request", () =>
Effect.gen(function* () {
mockedExecute
.mockReturnValueOnce(
Effect.succeed(
// @effect-diagnostics-next-line preferSchemaOverJson:off
output(JSON.stringify({ data: { repository: { pullRequest: { id: "PR_1" } } } })),
),
)
.mockReturnValueOnce(Effect.succeed(output("{}")));
const cli = yield* GitHubPullRequestCli.GitHubPullRequestCli;

yield* cli.setPullRequestFilesViewed({
cwd: "/w",
repository: "acme/web",
host: "github.com",
number: 7,
files: [
{ path: "src/a.ts", viewed: true },
{ path: "src/b.ts", viewed: false },
],
});

// One request to learn the pull request's node id, one for every press together.
assert.strictEqual(mockedExecute.mock.calls.length, 2);
// @effect-diagnostics-next-line preferSchemaOverJson:off
const sent = JSON.parse(callAt(1).stdin ?? "") as {
query: string;
variables: Record<string, string>;
};
expect(sent.query).toContain("f0: markFileAsViewed");
expect(sent.query).toContain("f1: unmarkFileAsViewed");
expect(sent.variables).toEqual({
pullRequestId: "PR_1",
path0: "src/a.ts",
path1: "src/b.ts",
});
}),
);

it.effect("asks the host nothing when nothing was pressed", () =>
Effect.gen(function* () {
const cli = yield* GitHubPullRequestCli.GitHubPullRequestCli;

yield* cli.setPullRequestFilesViewed({
cwd: "/w",
repository: "acme/web",
host: "github.com",
number: 7,
files: [],
});

assert.strictEqual(mockedExecute.mock.calls.length, 0);
}),
);
});
92 changes: 92 additions & 0 deletions apps/server/src/pullRequest/GitHubPullRequestCli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
resolvePullRequestAuthorFilter,
type PullRequestAction,
type PullRequestActor,
type PullRequestFileViewed,
type PullRequestInvolvement,
type PullRequestListFilters,
type PullRequestListState,
Expand All @@ -30,10 +31,12 @@ import {
ADD_REACTION_GRAPHQL_MUTATION,
buildReviewSubmissionJson,
buildReviewerRequestJson,
buildSetFilesViewedGraphQlMutation,
decodeActorAvatarsJson,
decodePullRequestActivityJson,
decodePullRequestDetailJson,
decodePullRequestFilesJson,
decodePullRequestFilesViewedJson,
decodePullRequestListJson,
decodePullRequestNodeIdJson,
decodePullRequestSearchJson,
Expand All @@ -53,6 +56,7 @@ import {
decodeBaseComparisonJson,
PULL_REQUEST_DETAIL_JSON_FIELDS,
PULL_REQUEST_LIST_JSON_FIELDS,
PULL_REQUEST_FILES_VIEWED_GRAPHQL_QUERY,
PULL_REQUEST_NODE_ID_GRAPHQL_QUERY,
REACTION_SUBJECT_PULL_REQUEST_GRAPHQL_QUERY,
REMOVE_REACTION_GRAPHQL_MUTATION,
Expand Down Expand Up @@ -263,6 +267,12 @@ const PULL_REQUEST_FALLBACK_MAX_ROWS = 1_000;

/** What the files API serves at most in one response, which is what one slice is made of. */
const DIFF_FILES_PAGE_SIZE = 100;
/**
* How many hundred-file pages of viewed state one read will walk. A point of the hourly GraphQL
* budget per page, against a change request nobody reviews in one sitting past the first few
* hundred files: beyond this the read stops and says it was cut short.
*/
const FILES_VIEWED_MAX_PAGES = 5;

/**
* Pages of review threads to follow before the conversation is reported as truncated. GitHub
Expand Down Expand Up @@ -308,6 +318,12 @@ export interface GitHubPullRequestDiffSlice {
readonly omittedFileStats?: ReadonlyArray<PullRequestOmittedFileStat>;
}

export interface GitHubPullRequestFilesViewed {
readonly files: ReadonlyArray<PullRequestFileViewed>;
/** GitHub had more files than the page budget below would read. */
readonly truncated: boolean;
}

export class GitHubPullRequestCli extends Context.Service<
GitHubPullRequestCli,
{
Expand Down Expand Up @@ -415,6 +431,30 @@ export class GitHubPullRequestCli extends Context.Service<
GitHubPullRequestCliError
>;

/**
* Which files of the pull request the signed-in account has cleared, and which of those have
* been pushed to since. Read apart from the patch because GitHub only reports it over GraphQL,
* and because the two answers go stale at completely different rates.
*/
readonly getPullRequestFilesViewed: (input: {
readonly cwd: string;
readonly repository: string;
readonly host: string;
readonly number: number;
}) => Effect.Effect<GitHubPullRequestFilesViewed, GitHubPullRequestCliError>;

/**
* Clears files, or puts them back, as one request. GitHub takes a single path per mutation,
* so a burst is batched with aliases into one document rather than one subprocess per press.
*/
readonly setPullRequestFilesViewed: (input: {
readonly cwd: string;
readonly repository: string;
readonly host: string;
readonly number: number;
readonly files: ReadonlyArray<{ readonly path: string; readonly viewed: boolean }>;
}) => Effect.Effect<void, GitHubPullRequestCliError>;

readonly listReviewThreadComments: (input: {
readonly cwd: string;
readonly repository: string;
Expand Down Expand Up @@ -1763,6 +1803,58 @@ export const make = Effect.gen(function* () {
variables: { threadId: input.threadId, body: input.body },
}),

getPullRequestFilesViewed: (input) => {
const { owner, name } = parseRepositorySelector(input.repository);
const read = (
after: string | null,
collected: ReadonlyArray<PullRequestFileViewed>,
pagesLeft: number,
): Effect.Effect<GitHubPullRequestFilesViewed, GitHubPullRequestCliError> =>
graphqlRead({
cwd: input.cwd,
host: input.host,
operation: "getPullRequestFilesViewed",
variables: [
["-f", `owner=${owner}`],
["-f", `name=${name}`],
["-F", `number=${input.number}`],
...(after === null
? []
: ([["-f", `after=${after}`]] as ReadonlyArray<readonly [string, string]>)),
],
query: PULL_REQUEST_FILES_VIEWED_GRAPHQL_QUERY,
decode: decodePullRequestFilesViewedJson,
}).pipe(
Effect.flatMap((page) => {
const files = [...collected, ...page.files];
if (page.nextCursor === null) {
return Effect.succeed({ files, truncated: false });
}
// A change nobody could read in one sitting is not worth a point of budget a page:
// the boxes on screen still work, and the count says it is partial rather than lying.
return pagesLeft <= 1
? Effect.succeed({ files, truncated: true })
: read(page.nextCursor, files, pagesLeft - 1);
}),
);
return read(null, [], FILES_VIEWED_MAX_PAGES);
},

setPullRequestFilesViewed: (input) => {
const mutation = buildSetFilesViewedGraphQlMutation(input.files);
if (mutation === null) return Effect.void;
return pullRequestNodeId({ ...input, operation: "setPullRequestFilesViewed" }).pipe(
Comment thread
yordis marked this conversation as resolved.
Effect.flatMap((pullRequestId) =>
graphql({
cwd: input.cwd,
host: input.host,
query: mutation.query,
variables: { pullRequestId, ...mutation.variables },
}),
),
);
},

setReviewThreadResolution: (input) =>
graphql({
cwd: input.cwd,
Expand Down
7 changes: 7 additions & 0 deletions apps/server/src/pullRequest/GitHubPullRequestProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const CAPABILITIES: PullRequestCapabilities = {
updateMethods: ["merge", "rebase"],
search: true,
reactions: true,
viewedFiles: true,
review: {
inlineComment: true,
reply: true,
Expand Down Expand Up @@ -399,6 +400,12 @@ export const make = Effect.gen(function* () {
getDiffFileContents: (input) =>
cli.getPullRequestDiffFileContents(input).pipe(Effect.mapError(fail("getDiffFileContents"))),

getFilesViewed: (input) =>
cli.getPullRequestFilesViewed(input).pipe(Effect.mapError(fail("getFilesViewed"))),

setFilesViewed: (input) =>
cli.setPullRequestFilesViewed(input).pipe(Effect.mapError(fail("setFilesViewed"))),

listReviewerCandidates: (input) =>
cli.listReviewerCandidates(input).pipe(Effect.mapError(fail("listReviewerCandidates"))),

Expand Down
30 changes: 30 additions & 0 deletions apps/server/src/pullRequest/PullRequestProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
PullRequestChecksState,
PullRequestCheck,
PullRequestComment,
PullRequestFileViewed,
PullRequestCommit,
PullRequestInvolvement,
PullRequestLabel,
Expand Down Expand Up @@ -201,6 +202,12 @@ export interface ProviderDiffFileContents {
readonly newContents: string;
}

export interface ProviderFilesViewed {
readonly files: ReadonlyArray<PullRequestFileViewed>;
/** The host has more files than were read, so the ones missing here are not "unviewed". */
readonly truncated: boolean;
}

export interface ProviderRepositoryRef {
readonly cwd: string;
/** Provider-native repository identity, e.g. `owner/repo` or `group/subgroup/project`. */
Expand Down Expand Up @@ -355,6 +362,29 @@ export interface PullRequestProviderApi {
},
) => Effect.Effect<ProviderDiffFileContents, PullRequestProviderError>;

/**
* Which files the reader has already cleared. Only called when `capabilities.viewedFiles` is
* true, and read apart from the patch: a host that reports this at all reports it on a clock of
* its own, moving with every press rather than with every push.
*/
readonly getFilesViewed?: (
input: ProviderRepositoryRef & { readonly number: number },
) => Effect.Effect<ProviderFilesViewed, PullRequestProviderError>;

/**
* Clears files, or puts them back. Only called when `capabilities.viewedFiles` is true.
*
* Takes several at once because that is how they are pressed. A provider whose host has no
* bulk form still owes one round trip for the batch rather than one per file, since the point
* of gathering them here is that the host is asked once.
*/
readonly setFilesViewed?: (
input: ProviderRepositoryRef & {
readonly number: number;
readonly files: ReadonlyArray<{ readonly path: string; readonly viewed: boolean }>;
},
) => Effect.Effect<void, PullRequestProviderError>;

readonly runAction: (
input: ProviderRepositoryRef & {
readonly number: number;
Expand Down
Loading
Loading