@effected/github 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -9,12 +9,9 @@ import { SemVer } from "@effected/semver";
9
9
  * Why a GitHub call failed, as a value you can branch on.
10
10
  *
11
11
  * @remarks
12
- * This discriminant is what replaces string-matching an error message. The
13
- * package this replaces carried a free-form `reason` string and nothing else
14
- * structural, so consumers grepped it: one repo lowercased a GraphQL message and
15
- * tested `includes("already") || includes("exists")`, and another re-issued an
16
- * existence check after every failed branch creation because it could not tell
17
- * "someone else created it" from "that failed".
12
+ * Branch on this discriminant instead of string-matching an error message:
13
+ * `alreadyExists` tells "someone else created it" apart from "that failed", so
14
+ * an upsert needs no follow-up existence check.
18
15
  *
19
16
  * @public
20
17
  */
@@ -75,8 +72,8 @@ declare const GitHubError_base: Schema.Class<GitHubError, Schema.TaggedStruct<"G
75
72
  * @remarks
76
73
  * Written by the client from `retry-after` or the rate-limit reset, and read
77
74
  * by exactly one thing: the retry `Schedule`. It is a policy input, not
78
- * information for a caller — which is why it is optional and why the
79
- * `retryable` boolean it used to travel with is now a derived getter.
75
+ * information for a caller. Whether a failure is worth retrying at all is the
76
+ * derived `retryable` getter.
80
77
  */
81
78
  readonly retryAfterMillis: Schema.optionalKey<Schema.Int>;
82
79
  /**
@@ -95,16 +92,9 @@ declare const GitHubError_base: Schema.Class<GitHubError, Schema.TaggedStruct<"G
95
92
  * Every REST failure this package produces, from every resource.
96
93
  *
97
94
  * @remarks
98
- * One error class, not one per resource. Across the six repos surveyed for this
99
- * port, consumers read `reason` about forty times, `status` twice, `operation`
100
- * twice, and matched a resource-specific `_tag` exactly **once** — at a call
101
- * site that disappears entirely now that `GitBranch.upsert` exists. Eighteen
102
- * near-identical error classes and thirteen near-identical mapper closures
103
- * bought that one match.
104
- *
105
- * What replaces them is {@link GitHubErrorKind} for routing and `operation` for
106
- * identification. This mirrors `@effected/git`, where the rule is that no
107
- * consumer ever string-matches stderr because classification happens once.
95
+ * One error class, not one per resource: {@link GitHubErrorKind} routes and
96
+ * `operation` identifies what was attempted. This mirrors `@effected/git`,
97
+ * where classification happens once so no consumer string-matches stderr.
108
98
  *
109
99
  * @public
110
100
  */
@@ -134,7 +124,7 @@ export declare class GitHubError extends GitHubError_base {
134
124
  * @remarks
135
125
  * The single classification step for the whole package — every resource
136
126
  * method's failures come through here, so the taxonomy cannot drift between
137
- * resources the way thirteen hand-written mapper closures did.
127
+ * resources.
138
128
  *
139
129
  * `nowMillis` is passed in rather than read from the wall clock so the
140
130
  * function stays pure and total: the rate-limit reset header is an absolute
@@ -201,9 +191,8 @@ declare const GitHubGraphQLError_base: Schema.Class<GitHubGraphQLError, Schema.T
201
191
  *
202
192
  * @remarks
203
193
  * `"alreadyExists"` exists here for the same reason it exists on the REST
204
- * error: without it a consumer lowercases the message and greps it for
205
- * `"already"` and `"exists"`, which is exactly what one surveyed repo did to
206
- * make project creation idempotent.
194
+ * error: it lets a caller make a create idempotent without lowercasing the
195
+ * message and grepping it.
207
196
  */
208
197
  readonly kind: Schema.Literals<readonly ["alreadyExists", "notFound", "rejected", "unauthorized", "rateLimited", "transport", "decode"]>;
209
198
  /** The document's name, e.g. `"linkedIssues"` — never the literal `"graphql"`. */
@@ -223,7 +212,7 @@ declare const GitHubGraphQLError_base: Schema.Class<GitHubGraphQLError, Schema.T
223
212
  * @remarks
224
213
  * Separate from `GitHubError` because GraphQL genuinely answers differently:
225
214
  * a 200 response can still carry failures, and it carries a **list** of them.
226
- * `errors` is the one structured field a surveyed consumer actually read.
215
+ * `errors` carries every entry GitHub reported, in order.
227
216
  *
228
217
  * @public
229
218
  */
@@ -250,25 +239,29 @@ export declare class GitHubGraphQLError extends GitHubGraphQLError_base {
250
239
  *
251
240
  * @remarks
252
241
  * This is the mechanism that makes `client.graphql` return a **domain value**
253
- * rather than an `unknown` the caller casts. The package this replaces took a
254
- * query string and a caller-chosen type parameter with nothing connecting them,
255
- * so every consumer wrote its own response interface and hoped.
242
+ * rather than an `unknown` the caller casts: the response schema ties the
243
+ * query to its decoded type.
256
244
  *
257
- * The kit owns the documents its resources need; a consumer with a domain of
258
- * its own — silk-sync-action's ProjectV2 work, for instance — builds its own
259
- * `GraphQLDocument` and gets the same typing and the same error taxonomy
260
- * without this package having to know about its schema.
245
+ * This package owns the documents its resource services need; a consumer with a
246
+ * domain of its own (GitHub Projects, say) builds its own `GraphQLDocument` and
247
+ * gets the same typing and the same error taxonomy.
261
248
  *
262
249
  * @example
263
250
  * ```ts
264
- * import { GraphQLDocument } from "@effected/github";
265
- * import { Schema } from "effect";
266
- *
267
- * const ViewerLogin = GraphQLDocument.make({
268
- * name: "viewerLogin",
269
- * document: `query { viewer { login } }`,
270
- * response: Schema.Struct({ viewer: Schema.Struct({ login: Schema.String }) }),
271
- * })<{ readonly login: string }>();
251
+ * import { GitHubClient, GraphQLDocument } from "@effected/github";
252
+ * import { Effect, Schema } from "effect";
253
+ *
254
+ * const OwnerLogin = GraphQLDocument.make({
255
+ * name: "ownerLogin",
256
+ * document: `query ($owner: String!) { repositoryOwner(login: $owner) { login } }`,
257
+ * response: Schema.Struct({ repositoryOwner: Schema.NullOr(Schema.Struct({ login: Schema.String })) }),
258
+ * })<{ readonly owner: string }>();
259
+ *
260
+ * const login = Effect.gen(function* () {
261
+ * const client = yield* GitHubClient;
262
+ * const data = yield* client.graphql(OwnerLogin, { owner: "effect-ts" });
263
+ * return data.repositoryOwner?.login;
264
+ * });
272
265
  * ```
273
266
  *
274
267
  * @public
@@ -324,11 +317,8 @@ declare const RateLimitSnapshot_base: Schema.Class<RateLimitSnapshot, Schema.Str
324
317
  * one. Read it through the client's `rateLimit` member when you want to pace
325
318
  * yourself — **nothing in this package throttles on your behalf.**
326
319
  *
327
- * The package this replaces coupled the writer and the reader through an
328
- * optional shared `Ref` service that both resolved with `Effect.serviceOption`,
329
- * so an application that forgot to provide it got two private cells and a
330
- * silently dead feature. Here the cell lives inside the client layer that writes
331
- * it, and this is the only way to read it.
320
+ * The cell lives inside the client layer that writes it, so there is nothing
321
+ * extra to provide: reading it through the client is the only way.
332
322
  *
333
323
  * @public
334
324
  */
@@ -379,15 +369,22 @@ declare const RetryPolicy_base: Schema.Class<RetryPolicy, Schema.Struct<{
379
369
  *
380
370
  * @remarks
381
371
  * There is exactly **one** retry policy in this package, and it is wired into
382
- * the client so every resource inherits it and no resource carries its own. The
383
- * package this replaces shipped four mutually inconsistent policies — a
384
- * hand-rolled recursive loop, a second exported `Schedule` that ignored
385
- * server-advised delays, a per-operation branch retry layered on top of the
386
- * client's, and a rate-limiter retry with no predicate at all, which cheerfully
387
- * retried permission denials — and consumers added two more on top.
372
+ * the client so every resource inherits it and no resource carries its own.
388
373
  *
389
- * Only failures that report `retryable` are retried, which for `GitHubError` means a transport failure or a rate limit. A 404, a
390
- * validation rejection and an authorization failure fail on the first attempt.
374
+ * Only failures that report `retryable` are retried, which for `GitHubError`
375
+ * means a transport failure or a rate limit. A 404, a validation rejection and
376
+ * an authorization failure fail on the first attempt.
377
+ *
378
+ * @example
379
+ * ```ts
380
+ * import { GitHubClient, RetryPolicy } from "@effected/github";
381
+ * import { Duration, Redacted } from "effect";
382
+ *
383
+ * const layer = GitHubClient.layerFromToken({
384
+ * token: Redacted.make("ghp_example"),
385
+ * retry: RetryPolicy.make({ ...RetryPolicy.default, maxRetries: 2, maxDelay: Duration.seconds(10) }),
386
+ * });
387
+ * ```
391
388
  *
392
389
  * @public
393
390
  */
@@ -427,9 +424,7 @@ export declare class RetryPolicy extends RetryPolicy_base {
427
424
  * Built on `Schedule.modifyDelay`, whose callback receives the schedule's
428
425
  * `Metadata` — including the **input that failed**. That is what makes a
429
426
  * header-driven policy expressible as a `Schedule` at all: the delay is a
430
- * function of the error, not only of the attempt number. Not knowing this was
431
- * available is why the package this replaces hand-rolled a recursive retry
432
- * loop instead of using `Effect.retry`.
427
+ * function of the error, not only of the attempt number.
433
428
  */
434
429
  schedule<E extends RetryableFailure>(): Schedule.Schedule<number, E>;
435
430
  }
@@ -459,7 +454,7 @@ type Route = keyof Endpoints;
459
454
  * @remarks
460
455
  * octokit's own `RequestParameters` carries an `[parameter: string]: unknown`
461
456
  * index signature, so intersecting it would silently accept every misspelled
462
- * parameter. These three are the ones the surveyed call sites genuinely need:
457
+ * parameter. These three are the ones callers need:
463
458
  * `headers` for a release asset's `content-type` and the attestations API
464
459
  * version pin, `mediaType.format` for raw content reads, and `baseUrl` for the
465
460
  * `uploads.github.com` host that release-asset uploads go to. Everything else a
@@ -500,8 +495,7 @@ type Data<R extends Route> = Endpoints[R]["response"]["data"];
500
495
  * The subset of routes that paginate.
501
496
  *
502
497
  * @remarks
503
- * Handing a non-paginating route to a paginating call is a **compile** error,
504
- * which the string-keyed surface this package replaces could not express.
498
+ * Handing a non-paginating route to a paginating call is a **compile** error.
505
499
  *
506
500
  * Intersected with `Rest.Route` because `plugin-paginate-rest` generates its
507
501
  * map from its own `@octokit/types` pin, which can trail the one this package
@@ -536,10 +530,8 @@ declare const PageOptions_base: Schema.Class<PageOptions, Schema.Struct<{
536
530
  * How far a paginated read should go.
537
531
  *
538
532
  * @remarks
539
- * Both fields are honored by every paginating method in this package. The
540
- * package it replaces accepted them on the client and then passed `{}` at six
541
- * of its eight call sites, so callers silently got 100-item pages and an
542
- * unbounded walk with no way to say otherwise.
533
+ * Both fields are honored by every paginating method in this package. Unset,
534
+ * a read requests 100-item pages and walks until GitHub stops.
543
535
  *
544
536
  * `perPage` is **validated, not clamped**: GitHub caps a page at 100 and
545
537
  * silently ignores anything larger, so a caller asking for 250 has a bug whose
@@ -702,19 +694,17 @@ interface GitHubFixtures {
702
694
  * A missing fixture is a **test wiring** mistake, not a condition the code
703
695
  * under test should handle, so the default kills the fiber rather than
704
696
  * entering the error channel — the same treatment an absent `graphql`
705
- * fixture has always had.
697
+ * fixture gets.
706
698
  *
707
- * The default used to be `"fail"`, and the reason it changed is worth
708
- * knowing before you set it back: **a typed failure is only loud in code
709
- * that does not catch.** A consumer whose methods each catch `GitHubError`
710
- * and report it — a per-resource sync, say — turns a missing stub into a
711
- * *different execution path* rather than a failure, and the assertions then
712
- * fail for a new reason with nothing in any message naming a fixture. That
713
- * cost `@spencerbeggs/reposets` 28 tests reading as ordinary logic bugs.
699
+ * Prefer `"die"` to `"fail"`: **a typed failure is only loud in code that
700
+ * does not catch.** Code whose methods each catch `GitHubError` and report
701
+ * it — a per-resource sync, say — turns a missing stub into a *different
702
+ * execution path* rather than a failure, and the assertions then fail for a
703
+ * new reason with nothing in any message naming a fixture.
714
704
  *
715
705
  * - `"die"` — defect naming the route. Loud in every consumer.
716
- * - `"fail"` — the old behaviour: `GitHubError.notFound`. Rarely what you
717
- * want now that a recorded `GitHubError` value stubs a failure explicitly:
706
+ * - `"fail"` — fail with `GitHubError.notFound`. Rarely what you want, since
707
+ * a recorded `GitHubError` value stubs a failure explicitly:
718
708
  * `{ "GET /repos/{owner}/{repo}": GitHubError.notFound("read", "repo") }`
719
709
  * says which route fails and why, where absence says only "unwired".
720
710
  * - `"empty"` — serve `{}` for a request and no items for a paginated read.
@@ -735,11 +725,6 @@ interface GitHubFixtures {
735
725
  * **params** they were called with, which is what lets a suite assert that a
736
726
  * method sent the right `owner`/`repo`/body rather than only the right
737
727
  * route. `graphql` records the document name as `route`.
738
- *
739
- * Recording params was added for the resource modules ported in from
740
- * `@spencerbeggs/reposets`, whose ~80-line hand-rolled harness existed
741
- * because every one of their methods goes through `request` and a fixture
742
- * could assert nothing about them.
743
728
  */
744
729
  readonly requested?: Array<RecordedCall> | undefined;
745
730
  }
@@ -754,12 +739,27 @@ declare const GitHubClient_base: Context.ServiceClass<GitHubClient, "@effected/g
754
739
  * literal and gets both sides typed, with no callback, no type parameter to
755
740
  * invent, and no cast.
756
741
  *
757
- * That is the whole point of this package. The surface it replaces was
758
- * `rest<T>(operation: string, fn: (octokit: any) => Promise<{ data: T }>)`,
759
- * where `T` was whatever the caller wrote and nothing connected it to the
760
- * endpoint. Four consumer repos paid for that with sixteen cast sites and three
761
- * hand-written octokit interfaces, one of which gave up and typed its methods as
762
- * `Record<string, (p: unknown) => Promise<{ data: unknown }>>`.
742
+ * Nothing here asks the caller to invent a response type: the route literal is
743
+ * the only thing written, and a mismatch between a route and its parameters is
744
+ * a compile error.
745
+ *
746
+ * @example
747
+ * ```ts
748
+ * import { GitHubClient } from "@effected/github";
749
+ * import { Effect, Redacted } from "effect";
750
+ *
751
+ * const program = Effect.gen(function* () {
752
+ * const client = yield* GitHubClient;
753
+ * const release = yield* client.request("GET /repos/{owner}/{repo}/releases/latest", {
754
+ * owner: "effect-ts",
755
+ * repo: "effect",
756
+ * });
757
+ * return release.tag_name;
758
+ * });
759
+ *
760
+ * const layer = GitHubClient.layerFromToken({ token: Redacted.make("ghp_example") });
761
+ * Effect.runPromise(program.pipe(Effect.provide(layer)));
762
+ * ```
763
763
  *
764
764
  * @public
765
765
  */
@@ -782,10 +782,7 @@ export declare class GitHubClient extends GitHubClient_base {
782
782
  * provides a provider instead of mutating the environment and a non-Actions
783
783
  * consumer can source the token however it likes.
784
784
  *
785
- * Construction fails with core's `ConfigError` — an honest "no token is
786
- * configured". The layer this replaces failed with a **wire-failure** error
787
- * type instead, which is why one consumer wrapped it in `Layer.orDie` under a
788
- * five-line comment explaining that the error did not mean what it said.
785
+ * Construction fails with core's `ConfigError` when no token is configured.
789
786
  */
790
787
  static readonly layerFromConfig: (options?: Omit<GitHubClientOptions, "token"> & {
791
788
  readonly name?: string | undefined;
@@ -810,17 +807,11 @@ export declare class GitHubClient extends GitHubClient_base {
810
807
  * A double over recorded responses that **pages them for real**.
811
808
  *
812
809
  * @remarks
813
- * The one recorded-response double in this package, and the single narrow
814
- * exception to the no-behavior-reimplementing-doubles rule — safe precisely
815
- * because it reimplements nothing: it builds a `PageSource` over the recorded
810
+ * The recorded-response double in this package. It reimplements no behavior:
811
+ * it builds a `PageSource` over the recorded
816
812
  * array and hands it to the same `paginate` engine the live client uses, so
817
813
  * `perPage` and `maxPages` cannot behave differently here than in production.
818
814
  *
819
- * The double it replaces named its pagination parameters `_options` and
820
- * ignored them, returning every recorded page regardless of what the caller
821
- * asked for — which made every truncation path in every consumer
822
- * structurally untestable.
823
- *
824
815
  * `fixtures.requested` is appended to as the test runs, so a suite can assert
825
816
  * which routes were walked and at what page size.
826
817
  */
@@ -875,33 +866,26 @@ declare const Repo_base: Context.ServiceClass<Repo, "@effected/github/Repo", Rep
875
866
  * `{ owner, repo }` argument**, which is what makes a read like
876
867
  * `GitHubRepository.defaultBranch` a single expression instead of a preamble.
877
868
  *
878
- * The package this replaces read `process.env.GITHUB_REPOSITORY` in three
879
- * places — inside the client, inside the App layer, and transitively in every
880
- * caller of `client.repo` — which is most of what coupled a GitHub API client to
881
- * the GitHub Actions runtime. Here the coordinate is a value, the env-driven way
882
- * to get one is a layer variant **named for being env-driven**, and a program
883
- * that acts on several repositories uses {@link Repo.provide}:
869
+ * The coordinate is a plain value. The only env-driven way to get one is
870
+ * {@link Repo.layerFromConfig}, which is named for being env-driven, and a
871
+ * program that acts on several repositories uses {@link Repo.provide}.
872
+ *
873
+ * The service shape is entirely one immutable value (a `RepoRef`), with no
874
+ * methods, so `Layer.succeed` is the correct test double.
884
875
  *
885
876
  * @example
886
877
  * ```ts
887
- * import { Repo } from "@effected/github";
878
+ * import { Repo, RepoRef } from "@effected/github";
888
879
  * import { Effect } from "effect";
889
880
  *
890
881
  * declare const syncOne: Effect.Effect<void, never, Repo>;
891
- * declare const targets: ReadonlyArray<Repo["Service"]>;
882
+ * declare const targets: ReadonlyArray<RepoRef>;
892
883
  *
893
884
  * const syncAll = Effect.forEach(targets, (target) => syncOne.pipe(Repo.provide(target)), {
894
885
  * concurrency: 4,
895
886
  * });
896
887
  * ```
897
888
  *
898
- * **A deliberate exception to "no non-effectful members on a service shape."**
899
- * This shape is entirely one immutable value: there is nothing to leave
900
- * unimplemented, so `Layer.mock` has nothing to degrade and `Layer.succeed` is
901
- * the correct double. The rule exists to stop a sync member from quietly
902
- * degrading a *mixed* shape's partial mock. The boundary to hold: the moment a
903
- * method appears here, this is a service again and the rule applies.
904
- *
905
889
  * @public
906
890
  */
907
891
  export declare class Repo extends Repo_base {
@@ -943,10 +927,7 @@ declare const StorageRecordInput_base: Schema.Class<StorageRecordInput, Schema.S
943
927
  * What to record about a published artifact.
944
928
  *
945
929
  * @remarks
946
- * These are the fields the endpoint actually accepts. The version this replaces
947
- * declared a `version` field the endpoint has no notion of — a fabricated key
948
- * that a `Record<string, unknown>` body accepted silently and the generated
949
- * types reject outright.
930
+ * These are the fields the storage-record endpoint accepts.
950
931
  *
951
932
  * @public
952
933
  */
@@ -957,9 +938,8 @@ export declare class StorageRecordInput extends StorageRecordInput_base {}
957
938
  * @remarks
958
939
  * The endpoint is org-scoped rather than repository-scoped, but the
959
940
  * organization is resolved from {@link Repo}'s `owner` per call like every
960
- * other resource — an earlier version took it as a positional argument, the
961
- * one method on the surface that did. `Repo.provide` covers the cross-org
962
- * case, exactly as it covers the cross-repository one.
941
+ * other resource. `Repo.provide` covers the cross-org case, exactly as it
942
+ * covers the cross-repository one.
963
943
  *
964
944
  * @public
965
945
  */
@@ -969,11 +949,16 @@ interface ArtifactMetadataShape {
969
949
  }
970
950
  declare const ArtifactMetadata_base: Context.ServiceClass<ArtifactMetadata, "@effected/github/ArtifactMetadata", ArtifactMetadataShape>;
971
951
  /**
972
- * Artifact metadata.
952
+ * Records where published artifacts are stored, at the organization level.
953
+ *
954
+ * @remarks
955
+ * Provide it with {@link ArtifactMetadata.layer}, which needs a `GitHubClient`;
956
+ * `createStorageRecord` also needs a `Repo` in `R`.
973
957
  *
974
958
  * @public
975
959
  */
976
960
  export declare class ArtifactMetadata extends ArtifactMetadata_base {
961
+ /** The live service, built over a `GitHubClient`. */
977
962
  static readonly layer: Layer.Layer<ArtifactMetadata, never, GitHubClient>;
978
963
  /** An in-memory double; unstubbed members die naming themselves. */
979
964
  static readonly makeTest: (overrides?: Partial<ArtifactMetadataShape>) => ArtifactMetadataShape;
@@ -1012,8 +997,7 @@ export declare class AttestationListEntry extends AttestationListEntry_base {}
1012
997
  * @remarks
1013
998
  * Upload and listing only. Building a statement, signing it and producing the
1014
999
  * bundle belong to `@effected/sbom`; assembling those into a pipeline belongs to
1015
- * the consumer. That split is what dissolves the five-service knot the previous
1016
- * package needed a mega-layer to test.
1000
+ * the consumer.
1017
1001
  *
1018
1002
  * @public
1019
1003
  */
@@ -1034,11 +1018,17 @@ interface AttestationShape {
1034
1018
  }
1035
1019
  declare const Attestation_base: Context.ServiceClass<Attestation, "@effected/github/Attestation", AttestationShape>;
1036
1020
  /**
1037
- * Attestations.
1021
+ * Uploads signed attestation bundles to a repository and lists what is attested
1022
+ * about a subject digest.
1023
+ *
1024
+ * @remarks
1025
+ * Provide it with {@link Attestation.layer}, which needs a `GitHubClient`; each
1026
+ * method also needs a `Repo` in `R`.
1038
1027
  *
1039
1028
  * @public
1040
1029
  */
1041
1030
  export declare class Attestation extends Attestation_base {
1031
+ /** The live service, built over a `GitHubClient`. */
1042
1032
  static readonly layer: Layer.Layer<Attestation, never, GitHubClient>;
1043
1033
  /** An in-memory double; unstubbed members die naming themselves. */
1044
1034
  static readonly makeTest: (overrides?: Partial<AttestationShape>) => AttestationShape;
@@ -1084,8 +1074,8 @@ declare const CheckRunOutput_base: Schema.Class<CheckRunOutput, Schema.Struct<{
1084
1074
  * GitHub's limits are **byte** limits, and that distinction is the whole reason
1085
1075
  * this class exists rather than a struct: `✅`, `❌`, `🦋` and `│` cost several
1086
1076
  * bytes each, so a character-count check passes while the request comes back
1087
- * 422 saying *"summary exceeds a maximum bytesize of 65535"*. One consumer hit
1088
- * exactly that and wrote the truncation by hand.
1077
+ * 422 saying *"summary exceeds a maximum bytesize of 65535"*. Use
1078
+ * {@link CheckRunOutput.truncated} to cut an output to fit.
1089
1079
  *
1090
1080
  * @public
1091
1081
  */
@@ -1140,7 +1130,11 @@ export declare class CheckRunRef extends CheckRunRef_base {}
1140
1130
  */
1141
1131
  type ConcludeCheckRun = (conclusion: (typeof CheckConclusion.literals)[number], output?: CheckRunOutput) => Effect.Effect<void>;
1142
1132
  /**
1143
- * Check runs.
1133
+ * Create, update and conclude GitHub check runs on a commit, including a
1134
+ * bracket that always concludes the run.
1135
+ *
1136
+ * @remarks
1137
+ * Every member resolves the target repository from the `Repo` service in `R`.
1144
1138
  *
1145
1139
  * @public
1146
1140
  */
@@ -1174,30 +1168,46 @@ interface CheckRunShape {
1174
1168
  * Neither an interrupt nor an existing failure is replaced by whatever went
1175
1169
  * wrong while reporting it.
1176
1170
  *
1177
- * `use` keeps its own `R` and its own `A`, unlike the version this replaces,
1178
- * whose callback was `R`-less and so forced consumers to build
1179
- * self-contained layers just to use the bracket.
1171
+ * `use` keeps its own `R` and its own `A`, so the bracket composes with
1172
+ * whatever services the wrapped work needs.
1180
1173
  *
1181
1174
  * @example
1182
1175
  * ```ts
1183
- * check.withCheckRun("lint", sha, (id, conclude) =>
1176
+ * import { CheckRun, CheckRunOutput } from "@effected/github";
1177
+ * import { Effect } from "effect";
1178
+ *
1179
+ * const lintWithCheck = (sha: string) =>
1184
1180
  * Effect.gen(function* () {
1185
- * const findings = yield* lint();
1186
- * yield* conclude(deriveConclusion(findings), report(findings));
1187
- * return findings;
1188
- * }),
1189
- * );
1181
+ * const check = yield* CheckRun;
1182
+ * return yield* check.withCheckRun("lint", sha, (_id, conclude) =>
1183
+ * Effect.gen(function* () {
1184
+ * const findings = 3; // run the linter here
1185
+ * // An advisory result: record "neutral" instead of the default "success".
1186
+ * yield* conclude(
1187
+ * "neutral",
1188
+ * CheckRunOutput.make({ title: "lint", summary: `${findings} findings` }),
1189
+ * );
1190
+ * return findings;
1191
+ * }),
1192
+ * );
1193
+ * });
1190
1194
  * ```
1191
1195
  */
1192
1196
  readonly withCheckRun: <A, E, R>(name: string, headSha: string, use: (id: number, conclude: ConcludeCheckRun) => Effect.Effect<A, E, R>) => Effect.Effect<A, E | GitHubError, R | Repo>;
1193
1197
  }
1194
1198
  declare const CheckRun_base: Context.ServiceClass<CheckRun, "@effected/github/CheckRun", CheckRunShape>;
1195
1199
  /**
1196
- * Check runs.
1200
+ * Create, update and conclude GitHub check runs, including the
1201
+ * {@link CheckRunShape.withCheckRun} bracket that always reaches a terminal state.
1202
+ *
1203
+ * @remarks
1204
+ * Provide it with {@link CheckRun.layer}, which needs a `GitHubClient`; each
1205
+ * method also needs a `Repo` in `R`.
1197
1206
  *
1198
1207
  * @public
1199
1208
  */
1200
1209
  export declare class CheckRun extends CheckRun_base {
1210
+ /** The live service, built over a `GitHubClient`. */
1201
1211
  static readonly layer: Layer.Layer<CheckRun, never, GitHubClient>;
1202
1212
  /** An in-memory double; unstubbed members die naming themselves. */
1203
1213
  static readonly makeTest: (overrides?: Partial<CheckRunShape>) => CheckRunShape;
@@ -1251,8 +1261,8 @@ interface CodeScanningShape {
1251
1261
  * the repository's workflows afterwards. A caller that treats "default setup
1252
1262
  * is off" as "no CodeQL workflow exists" will be wrong, and one that counts
1253
1263
  * workflows to decide whether a repository has any CI will count that one.
1254
- * Reported by `@spencerbeggs/reposets` (dogfood round 8, 2026-08-14) from a
1255
- * real organization, not inferred from the API description.
1264
+ * Observed against a real organization, not inferred from the API
1265
+ * description.
1256
1266
  */
1257
1267
  readonly configure: (setup: CodeScanningSetup) => Effect.Effect<void, GitHubError, Repo>;
1258
1268
  /**
@@ -1268,12 +1278,19 @@ interface CodeScanningShape {
1268
1278
  }
1269
1279
  declare const CodeScanning_base: Context.ServiceClass<CodeScanning, "@effected/github/CodeScanning", CodeScanningShape>;
1270
1280
  /**
1271
- * CodeQL default setup.
1281
+ * Configure CodeQL default setup and read the languages GitHub detects in a
1282
+ * repository.
1283
+ *
1284
+ * @remarks
1285
+ * Provide it with {@link CodeScanning.layer}, which needs a `GitHubClient`; each
1286
+ * method also needs a `Repo` in `R`.
1272
1287
  *
1273
1288
  * @public
1274
1289
  */
1275
1290
  export declare class CodeScanning extends CodeScanning_base {
1276
1291
  /**
1292
+ * The live service, built over a `GitHubClient`.
1293
+ *
1277
1294
  * @remarks
1278
1295
  * The callback is written `(client) => make(client)` rather than passed as
1279
1296
  * `make` directly, and that is load-bearing: a static initializer runs while
@@ -1295,10 +1312,11 @@ export declare class CodeScanning extends CodeScanning_base {
1295
1312
  * @public
1296
1313
  */
1297
1314
  interface DeploymentEnvironmentInfo {
1315
+ /** The environment's name. */
1298
1316
  readonly name: string;
1299
1317
  }
1300
1318
  /**
1301
- * Deployment environments.
1319
+ * Create or update, list and delete a repository's deployment environments.
1302
1320
  *
1303
1321
  * @public
1304
1322
  */
@@ -1330,12 +1348,30 @@ interface DeploymentEnvironmentShape {
1330
1348
  }
1331
1349
  declare const DeploymentEnvironment_base: Context.ServiceClass<DeploymentEnvironment, "@effected/github/DeploymentEnvironment", DeploymentEnvironmentShape>;
1332
1350
  /**
1333
- * Deployment environments.
1351
+ * Create or update, list and delete a repository's deployment environments.
1352
+ *
1353
+ * @remarks
1354
+ * Provide it with {@link DeploymentEnvironment.layer}, which needs a
1355
+ * `GitHubClient`; each method also needs a `Repo` in `R`.
1356
+ *
1357
+ * @example
1358
+ * ```ts
1359
+ * import { DeploymentEnvironment } from "@effected/github";
1360
+ * import { Effect } from "effect";
1361
+ *
1362
+ * const program = Effect.gen(function* () {
1363
+ * const environments = yield* DeploymentEnvironment;
1364
+ * yield* environments.upsert("production", { wait_timer: 10 });
1365
+ * return yield* environments.list();
1366
+ * });
1367
+ * ```
1334
1368
  *
1335
1369
  * @public
1336
1370
  */
1337
1371
  export declare class DeploymentEnvironment extends DeploymentEnvironment_base {
1338
1372
  /**
1373
+ * The live service, built over a `GitHubClient`.
1374
+ *
1339
1375
  * @remarks
1340
1376
  * `(client) => make(client)` rather than `make`: a static initializer runs
1341
1377
  * while the module body is still evaluating, so naming a `const` declared
@@ -1372,25 +1408,19 @@ interface GitBranchShape {
1372
1408
  * Point `name` at `sha`, creating it if needed.
1373
1409
  *
1374
1410
  * @remarks
1375
- * **One call, one intent.** Creating a branch that may already exist is the
1376
- * single most-repeated dance in the surveyed consumers: the marketplace
1377
- * manager spent a seven-line comment and a nine-line workaround on it, doing
1378
- * `getSha` → `exists` → `create` → on failure `exists` again → `reset`, up to
1379
- * four round trips, because the error it caught carried no structured
1380
- * "already exists". silk-release-action wrote the mirror image of the same
1381
- * dance a few files away.
1382
- *
1383
- * This is one round trip in the common case and two in the raced one, and the
1384
- * recovery **resets** rather than inheriting a branch a concurrent creator
1385
- * rooted somewhere else — which is the semantics that comment was defending.
1411
+ * **One call, one intent.** Creating a branch that may already exist needs no
1412
+ * `exists` check, no catch and no second attempt: this creates the ref, and
1413
+ * when GitHub answers `alreadyExists` it resets the ref to `sha`. It is one
1414
+ * round trip in the common case and two in the raced one, and the recovery
1415
+ * **resets** rather than inheriting a branch a concurrent creator rooted
1416
+ * somewhere else. The result says which happened: `"created"` or `"reset"`.
1386
1417
  *
1387
1418
  * **A reset is observable, and open pull requests react to it.** Resetting a
1388
1419
  * branch to its PR's base — `upsert(branch, targetHead)` — makes that PR's
1389
1420
  * head equal its base, and GitHub **auto-closes a PR whose diff is empty**.
1390
- * The window is invisible at this call site: a consumer ran
1391
- * `upsert(releaseBranch, mainHead)` intending to re-add content with a commit
1392
- * ~3 seconds later, and GitHub closed the open release PR inside that window
1393
- * while the run reported success. When the end state is "the target head plus
1421
+ * The window is invisible at this call site: `upsert(releaseBranch, mainHead)`
1422
+ * followed a few seconds later by a commit that re-adds content can lose an
1423
+ * open release PR in between while the run reports success. When the end state is "the target head plus
1394
1424
  * a commit", build the commit first — `GitCommit.get` the target for its
1395
1425
  * `treeSha`, `createTree` on it, `createCommit` with the target as parent —
1396
1426
  * and upsert **once**, straight to the finished sha, so the ref never rests
@@ -1427,12 +1457,32 @@ interface GitBranchShape {
1427
1457
  }
1428
1458
  declare const GitBranch_base: Context.ServiceClass<GitBranch, "@effected/github/GitBranch", GitBranchShape>;
1429
1459
  /**
1430
- * Branches, as refs.
1460
+ * Create, move, read and delete branch refs through GitHub's Git Database API,
1461
+ * with an `upsert` that needs no existence check.
1462
+ *
1463
+ * @remarks
1464
+ * Provide it with {@link GitBranch.layer}, which needs a `GitHubClient`; each
1465
+ * method also needs a `Repo` in `R`. Branch names are accepted as `main`,
1466
+ * `heads/main` or `refs/heads/main`.
1467
+ *
1468
+ * @example
1469
+ * ```ts
1470
+ * import { GitBranch } from "@effected/github";
1471
+ * import { Effect } from "effect";
1472
+ *
1473
+ * const ensureBranch = (name: string, sha: string) =>
1474
+ * Effect.gen(function* () {
1475
+ * const branches = yield* GitBranch;
1476
+ * return yield* branches.upsert(name, sha); // "created" | "reset"
1477
+ * });
1478
+ * ```
1431
1479
  *
1432
1480
  * @public
1433
1481
  */
1434
1482
  export declare class GitBranch extends GitBranch_base {
1435
1483
  /**
1484
+ * The live service, built over a `GitHubClient`.
1485
+ *
1436
1486
  * @remarks
1437
1487
  * The callback is written `(client) => make(client)` rather than passed as
1438
1488
  * `make` directly, and that is load-bearing: a static initializer runs while
@@ -1499,10 +1549,8 @@ declare const CommitRef_base: Schema.Class<CommitRef, Schema.Struct<{
1499
1549
  * A commit, projected to the three fields callers actually use.
1500
1550
  *
1501
1551
  * @remarks
1502
- * `treeSha` is here because two surveyed call sites dropped to a raw octokit
1503
- * cast for it alone, both with the comment *"the Git Data API's `base_tree`
1504
- * wants a tree SHA, not a commit SHA"* — the same eight lines written twice, in
1505
- * two files, for one string.
1552
+ * `treeSha` is here because the Git Data API's `base_tree` wants a tree SHA,
1553
+ * not a commit SHA.
1506
1554
  *
1507
1555
  * @public
1508
1556
  */
@@ -1544,9 +1592,7 @@ interface GitCommitShape {
1544
1592
  * `GitBranch.upsert` straight to the finished commit. Do **not** spell a
1545
1593
  * rebase as `upsert(branch, targetHead)` followed by `commitFiles`: between
1546
1594
  * those calls the branch *is* the target head, an open pull request from it
1547
- * has an empty diff, and GitHub auto-closes PRs in that state — a real
1548
- * consumer lost its open release PR to that ~3-second window while the run
1549
- * went green.
1595
+ * has an empty diff, and GitHub auto-closes PRs in that state.
1550
1596
  */
1551
1597
  readonly commitFiles: (options: {
1552
1598
  readonly branch: string;
@@ -1556,11 +1602,33 @@ interface GitCommitShape {
1556
1602
  }
1557
1603
  declare const GitCommit_base: Context.ServiceClass<GitCommit, "@effected/github/GitCommit", GitCommitShape>;
1558
1604
  /**
1559
- * Commits, trees and blobs.
1605
+ * Read commits and build trees and commits through GitHub's Git Database API,
1606
+ * including a one-call "commit these files onto a branch".
1607
+ *
1608
+ * @remarks
1609
+ * Provide it with {@link GitCommit.layer}, which needs a `GitHubClient`; each
1610
+ * method also needs a `Repo` in `R`. No local git runs: this is the REST API,
1611
+ * not `@effected/git`.
1612
+ *
1613
+ * @example
1614
+ * ```ts
1615
+ * import { FileContent, GitCommit } from "@effected/github";
1616
+ * import { Effect } from "effect";
1617
+ *
1618
+ * const writeNotes = Effect.gen(function* () {
1619
+ * const commits = yield* GitCommit;
1620
+ * return yield* commits.commitFiles({
1621
+ * branch: "docs/notes",
1622
+ * message: "docs: add notes",
1623
+ * changes: [FileContent.make({ path: "NOTES.md", content: "# Notes\n" })],
1624
+ * }); // the new commit's sha
1625
+ * });
1626
+ * ```
1560
1627
  *
1561
1628
  * @public
1562
1629
  */
1563
1630
  export declare class GitCommit extends GitCommit_base {
1631
+ /** The live service, built over a `GitHubClient`. */
1564
1632
  static readonly layer: Layer.Layer<GitCommit, never, GitHubClient>;
1565
1633
  /** An in-memory double; unstubbed members die naming themselves. */
1566
1634
  static readonly makeTest: (overrides?: Partial<GitCommitShape>) => GitCommitShape;
@@ -1671,9 +1739,8 @@ export declare class InstallationToken extends InstallationToken_base {
1671
1739
  * Whether this token is spent, `skew` before its stated expiry.
1672
1740
  *
1673
1741
  * @remarks
1674
- * Modelled **and enforced**. The package this replaces persisted `expiresAt`
1675
- * and read it nowhere, so a long `main` phase that outlived the hour simply
1676
- * started answering 401 with no explanation.
1742
+ * `skew` defaults to one minute, so a token is treated as spent slightly early
1743
+ * rather than answering 401 mid-request.
1677
1744
  */
1678
1745
  isExpired(nowMillis: number, skew?: Duration.Duration): boolean;
1679
1746
  /** The committer identity a commit made with this token should carry. */
@@ -1689,10 +1756,10 @@ declare const BotIdentity_base: Schema.Class<BotIdentity, Schema.Struct<{
1689
1756
  * Who a bot commits as.
1690
1757
  *
1691
1758
  * @remarks
1692
- * A **pure class**, not a service member. The package this replaces put
1693
- * `botIdentity(source?)` on the `GitHubApp` service shape as a plain synchronous
1694
- * method, which makes it required in every `Layer.mock` and silently degrades
1695
- * every partial double to a full implementation.
1759
+ * A **pure class**, not a `GitHubApp` service member: a synchronous method on
1760
+ * the service shape would be required in every `Layer.mock` and would silently
1761
+ * degrade every partial double to a full implementation. Get one from
1762
+ * `InstallationToken.botIdentity` or `AppIdentity.botIdentity`.
1696
1763
  *
1697
1764
  * @public
1698
1765
  */
@@ -1781,9 +1848,28 @@ declare const GitHubApp_base: Context.ServiceClass<GitHubApp, "@effected/github/
1781
1848
  * `@effected/commands`' service, for the same reason.
1782
1849
  *
1783
1850
  * The JWT signer is `universal-github-app-jwt` — zero dependencies, and
1784
- * `@octokit/auth-app`'s own JWT dependency. Taking it directly rather than
1785
- * taking `auth-app` leaves behind roughly half a megabyte of OAuth app, user and
1786
- * device-flow machinery that this package never calls.
1851
+ * `@octokit/auth-app`'s own JWT dependency.
1852
+ *
1853
+ * @example
1854
+ * ```ts
1855
+ * import { GitHubApp, GitHubClient } from "@effected/github";
1856
+ * import { Effect, Redacted } from "effect";
1857
+ *
1858
+ * const program = Effect.gen(function* () {
1859
+ * const client = yield* GitHubClient;
1860
+ * const accessible = yield* client.request("GET /installation/repositories", { per_page: 1 });
1861
+ * return accessible.total_count;
1862
+ * });
1863
+ *
1864
+ * // Mints an installation token on build, re-mints before expiry, revokes on release.
1865
+ * const layer = GitHubApp.clientLayer({
1866
+ * appId: "12345",
1867
+ * privateKey: Redacted.make("-----BEGIN PRIVATE KEY-----\n..."),
1868
+ * owner: "my-org",
1869
+ * });
1870
+ *
1871
+ * Effect.runPromise(Effect.provide(program, layer));
1872
+ * ```
1787
1873
  *
1788
1874
  * @public
1789
1875
  */
@@ -1806,11 +1892,12 @@ export declare class GitHubApp extends GitHubApp_base {
1806
1892
  * The token's lifetime is the layer's scope: it is minted on build and
1807
1893
  * **revoked on release**, best-effort, so a workflow does not leave live
1808
1894
  * credentials behind. It is also **re-minted automatically** a minute before
1809
- * it expires, which the package this replaces did not do — it persisted
1810
- * `expiresAt` and read it nowhere, so a `main` phase outliving the hour
1811
- * started answering 401 with nothing explaining why.
1895
+ * it expires, so a long-running program does not start answering 401 when
1896
+ * the hour ends.
1812
1897
  *
1813
- * A failure to obtain credentials surfaces to the caller as a
1898
+ * Building the layer mints the first token, so a misconfigured app fails
1899
+ * construction with `GitHubAppError`. After that, a failure to obtain
1900
+ * credentials surfaces to the caller as a
1814
1901
  * `GitHubError { kind: "unauthorized" }` carrying the `GitHubAppError` as its
1815
1902
  * cause: from a request's point of view, "could not authenticate" is an
1816
1903
  * authorization failure, and widening every method's error channel to say so
@@ -1837,22 +1924,19 @@ interface GitHubAppShape {
1837
1924
  * Mint an installation token.
1838
1925
  *
1839
1926
  * @remarks
1840
- * Used by `@effected/github-actions`' token bridge in a workflow's `pre`
1841
- * phase. Touches: nothing else on this shape.
1927
+ * `installationId` is used when given; otherwise the installation is
1928
+ * discovered from `owner`, or from the app's only installation.
1842
1929
  */
1843
1930
  readonly token: (request: TokenRequest) => Effect.Effect<InstallationToken, GitHubAppError>;
1844
1931
  /**
1845
- * Mint a token that is revoked when the scope closes.
1932
+ * Mint a token that is revoked, best-effort, when the scope closes.
1846
1933
  *
1847
1934
  * @remarks
1848
- * Touches: `token`, `revoke`.
1935
+ * Mints through `token` and releases through `revoke`.
1849
1936
  */
1850
1937
  readonly scopedToken: (request: TokenRequest) => Effect.Effect<InstallationToken, GitHubAppError, Scope.Scope>;
1851
1938
  /**
1852
1939
  * Revoke a token now.
1853
- *
1854
- * @remarks
1855
- * Used by the token bridge's `post` phase. Touches: nothing else.
1856
1940
  */
1857
1941
  readonly revoke: (token: Redacted.Redacted<string>) => Effect.Effect<void, GitHubAppError>;
1858
1942
  /**
@@ -1861,17 +1945,12 @@ interface GitHubAppShape {
1861
1945
  * @remarks
1862
1946
  * Supply `installationToken` when you have one: `GET /users/{slug}[bot]`
1863
1947
  * rejects an app JWT, so without it the lookup runs unauthenticated at
1864
- * GitHub's 60-requests-per-hour-per-IP limit. Touches: nothing else.
1948
+ * GitHub's 60-requests-per-hour-per-IP limit.
1865
1949
  */
1866
1950
  readonly identity: (request: AppCredentials & {
1867
1951
  readonly installationToken?: Redacted.Redacted<string> | undefined;
1868
1952
  }) => Effect.Effect<AppIdentity, GitHubAppError>;
1869
- /**
1870
- * Every installation of the app.
1871
- *
1872
- * @remarks
1873
- * Touches: nothing else.
1874
- */
1953
+ /** Every installation of the app. */
1875
1954
  readonly installations: (credentials: AppCredentials) => Effect.Effect<ReadonlyArray<Installation>, GitHubAppError>;
1876
1955
  }
1877
1956
  //#endregion
@@ -1949,14 +2028,14 @@ declare const CommitComparison_base: Schema.Class<CommitComparison, Schema.Struc
1949
2028
  */
1950
2029
  export declare class CommitComparison extends CommitComparison_base {}
1951
2030
  /**
1952
- * Reading commits.
2031
+ * Read commits, list them, compare two refs and list the files a commit touched.
1953
2032
  *
1954
2033
  * @public
1955
2034
  */
1956
2035
  interface GitHubCommitShape {
1957
- /** One commit. */
2036
+ /** Read one commit by sha or ref. */
1958
2037
  readonly get: (ref: string) => Effect.Effect<CommitSummary, GitHubError, Repo>;
1959
- /** Commits on a ref, newest first. */
2038
+ /** List commits reachable from `ref` (the default branch when omitted), newest first, optionally limited to those touching `path`. */
1960
2039
  readonly list: (options?: {
1961
2040
  readonly ref?: string | undefined;
1962
2041
  readonly path?: string | undefined;
@@ -1968,8 +2047,9 @@ interface GitHubCommitShape {
1968
2047
  * @remarks
1969
2048
  * GitHub paginates this **by commit**, while the single-commit read paginates
1970
2049
  * **by file** at 300 per page — so a one-commit comparison is permanently
1971
- * truncated at 300 files no matter what you pass. That is GitHub's constraint,
1972
- * recorded here rather than discovered later.
2050
+ * truncated at 300 files no matter what you pass. That is GitHub's
2051
+ * constraint; use {@link GitHubCommitShape.changedFiles} to page every file
2052
+ * of one commit.
1973
2053
  */
1974
2054
  readonly compare: (base: string, head: string) => Effect.Effect<CommitComparison, GitHubError, Repo>;
1975
2055
  /** The files one commit touched, paginated by file. */
@@ -1979,11 +2059,30 @@ interface GitHubCommitShape {
1979
2059
  }
1980
2060
  declare const GitHubCommit_base: Context.ServiceClass<GitHubCommit, "@effected/github/GitHubCommit", GitHubCommitShape>;
1981
2061
  /**
1982
- * Commits, as GitHub reports them.
2062
+ * Read commits, compare refs and list changed files through GitHub's commits
2063
+ * API.
2064
+ *
2065
+ * @remarks
2066
+ * Provide it with {@link GitHubCommit.layer}, which needs a `GitHubClient`; each
2067
+ * method also needs a `Repo` in `R`. For commits as Git Database objects (trees,
2068
+ * parents), use `GitCommit` instead.
2069
+ *
2070
+ * @example
2071
+ * ```ts
2072
+ * import { GitHubCommit } from "@effected/github";
2073
+ * import { Effect } from "effect";
2074
+ *
2075
+ * const changedSinceMain = Effect.gen(function* () {
2076
+ * const commits = yield* GitHubCommit;
2077
+ * const comparison = yield* commits.compare("main", "feature");
2078
+ * return comparison.files.map((file) => file.path);
2079
+ * });
2080
+ * ```
1983
2081
  *
1984
2082
  * @public
1985
2083
  */
1986
2084
  export declare class GitHubCommit extends GitHubCommit_base {
2085
+ /** The live service, built over a `GitHubClient`. */
1987
2086
  static readonly layer: Layer.Layer<GitHubCommit, never, GitHubClient>;
1988
2087
  /** An in-memory double; unstubbed members die naming themselves. */
1989
2088
  static readonly makeTest: (overrides?: Partial<GitHubCommitShape>) => GitHubCommitShape;
@@ -1993,7 +2092,7 @@ export declare class GitHubCommit extends GitHubCommit_base {
1993
2092
  //#endregion
1994
2093
  //#region src/GitHubContent.d.ts
1995
2094
  /**
1996
- * Reading a file out of a repository.
2095
+ * Read a text file out of a repository at a ref.
1997
2096
  *
1998
2097
  * @public
1999
2098
  */
@@ -2001,6 +2100,11 @@ interface GitHubContentShape {
2001
2100
  /**
2002
2101
  * A text file's contents at `ref`, or the default branch when `ref` is
2003
2102
  * omitted.
2103
+ *
2104
+ * @remarks
2105
+ * Fails `notFound` when the path does not exist, and `rejected` when it is a
2106
+ * directory, is not a regular file, or is too large for the contents API
2107
+ * (which answers an empty body above roughly a megabyte).
2004
2108
  */
2005
2109
  readonly getFile: (path: string, options?: {
2006
2110
  readonly ref?: string | undefined;
@@ -2012,11 +2116,29 @@ interface GitHubContentShape {
2012
2116
  }
2013
2117
  declare const GitHubContent_base: Context.ServiceClass<GitHubContent, "@effected/github/GitHubContent", GitHubContentShape>;
2014
2118
  /**
2015
- * Repository file contents.
2119
+ * Read a text file out of a repository at a ref, with absence as an `Option`
2120
+ * when you want it.
2121
+ *
2122
+ * @remarks
2123
+ * Provide it with {@link GitHubContent.layer}, which needs a `GitHubClient`;
2124
+ * each method also needs a `Repo` in `R`.
2125
+ *
2126
+ * @example
2127
+ * ```ts
2128
+ * import { GitHubContent } from "@effected/github";
2129
+ * import { Effect, Option } from "effect";
2130
+ *
2131
+ * const readme = Effect.gen(function* () {
2132
+ * const content = yield* GitHubContent;
2133
+ * const file = yield* content.getFileOption("README.md", { ref: "main" });
2134
+ * return Option.getOrElse(file, () => "");
2135
+ * });
2136
+ * ```
2016
2137
  *
2017
2138
  * @public
2018
2139
  */
2019
2140
  export declare class GitHubContent extends GitHubContent_base {
2141
+ /** The live service, built over a `GitHubClient`. */
2020
2142
  static readonly layer: Layer.Layer<GitHubContent, never, GitHubClient>;
2021
2143
  /** An in-memory double; unstubbed members die naming themselves. */
2022
2144
  static readonly makeTest: (overrides?: Partial<GitHubContentShape>) => GitHubContentShape;
@@ -2035,11 +2157,9 @@ declare const CommentMarker_base: Schema.Class<CommentMarker, Schema.Struct<{
2035
2157
  * The hidden marker that makes a comment findable again.
2036
2158
  *
2037
2159
  * @remarks
2038
- * A pure class, not a hardcoded string. The surface this replaces baked
2039
- * `<!-- savvy-web:${key} -->` into the library — one vendor's name, inside a
2040
- * package meant to be general. Here the namespace is the caller's, the marker is
2041
- * testable without a client, and the library has no opinion about whose comments
2042
- * these are.
2160
+ * The marker is `<!-- namespace:key -->`, an HTML comment appended to the body.
2161
+ * The namespace is the caller's, so the library has no opinion about whose
2162
+ * comments these are, and a marker is testable without a client.
2043
2163
  *
2044
2164
  * @public
2045
2165
  */
@@ -2055,13 +2175,14 @@ declare const CommentRecord_base: Schema.Class<CommentRecord, Schema.Struct<{
2055
2175
  readonly url: Schema.String;
2056
2176
  }>, {}>;
2057
2177
  /**
2058
- * A comment this package wrote or found.
2178
+ * A comment this package wrote or found: its id, body and web URL.
2059
2179
  *
2060
2180
  * @public
2061
2181
  */
2062
2182
  export declare class CommentRecord extends CommentRecord_base {}
2063
2183
  /**
2064
- * Sticky comments on a pull request or issue.
2184
+ * Post, update, find and delete comments on a pull request or issue, including
2185
+ * a "sticky" comment kept current through a marker.
2065
2186
  *
2066
2187
  * @public
2067
2188
  */
@@ -2080,22 +2201,42 @@ interface PullRequestCommentShape {
2080
2201
  * Find the marked comment.
2081
2202
  *
2082
2203
  * @remarks
2083
- * **Paginates.** The version this replaces requested a single page of 100 and
2084
- * stopped, so on a busy pull request the marker silently vanished and every
2085
- * update posted a new comment instead.
2204
+ * **Paginates**, so the marker is found on a busy pull request too; pass
2205
+ * `page` to bound the walk.
2086
2206
  */
2087
2207
  readonly find: (issueNumber: number, marker: CommentMarker, options?: {
2088
2208
  readonly page?: PageOptions | undefined;
2089
2209
  }) => Effect.Effect<Option.Option<CommentRecord>, GitHubError, Repo>;
2210
+ /** Delete a comment by id. */
2090
2211
  readonly delete: (commentId: number) => Effect.Effect<void, GitHubError, Repo>;
2091
2212
  }
2092
2213
  declare const PullRequestComment_base: Context.ServiceClass<PullRequestComment, "@effected/github/PullRequestComment", PullRequestCommentShape>;
2093
2214
  /**
2094
- * Sticky comments.
2215
+ * Post, update, find and delete comments on a pull request or issue, including
2216
+ * a "sticky" comment kept current through a `CommentMarker`.
2217
+ *
2218
+ * @remarks
2219
+ * Provide it with {@link PullRequestComment.layer}, which needs a `GitHubClient`;
2220
+ * each method also needs a `Repo` in `R`.
2221
+ *
2222
+ * @example
2223
+ * ```ts
2224
+ * import { CommentMarker, PullRequestComment } from "@effected/github";
2225
+ * import { Effect } from "effect";
2226
+ *
2227
+ * const marker = CommentMarker.make({ namespace: "my-action", key: "report" });
2228
+ *
2229
+ * const report = (pullNumber: number, body: string) =>
2230
+ * Effect.gen(function* () {
2231
+ * const comments = yield* PullRequestComment;
2232
+ * return yield* comments.upsert(pullNumber, marker, body); // edits the marked comment in place
2233
+ * });
2234
+ * ```
2095
2235
  *
2096
2236
  * @public
2097
2237
  */
2098
2238
  export declare class PullRequestComment extends PullRequestComment_base {
2239
+ /** The live service, built over a `GitHubClient`. */
2099
2240
  static readonly layer: Layer.Layer<PullRequestComment, never, GitHubClient>;
2100
2241
  /** An in-memory double; unstubbed members die naming themselves. */
2101
2242
  static readonly makeTest: (overrides?: Partial<PullRequestCommentShape>) => PullRequestCommentShape;
@@ -2131,10 +2272,8 @@ declare const LinkedIssue_base: Schema.Class<LinkedIssue, Schema.Struct<{
2131
2272
  * branch or commit messages.
2132
2273
  *
2133
2274
  * @remarks
2134
- * This is the field the whole document exists for. The version this replaces
2135
- * could not express `userLinkedOnly`, so one consumer re-declared the query
2136
- * with the field aliased twice to get it — the single largest duplicated
2137
- * document in the survey.
2275
+ * Resolved by querying the pull request's closing references twice, once with
2276
+ * `userLinkedOnly`, and marking the issues present in the second result.
2138
2277
  */
2139
2278
  readonly userLinked: Schema.Boolean;
2140
2279
  }>, {}>;
@@ -2162,19 +2301,28 @@ declare const CommentOnceResult_base: Schema.Class<CommentOnceResult, Schema.Str
2162
2301
  */
2163
2302
  export declare class CommentOnceResult extends CommentOnceResult_base {}
2164
2303
  /**
2165
- * Issues.
2304
+ * Read, list, close and comment on issues, and resolve the issues a pull
2305
+ * request closes.
2166
2306
  *
2167
2307
  * @public
2168
2308
  */
2169
2309
  interface GitHubIssueShape {
2310
+ /** Read one issue. Fails `notFound` when it does not exist. */
2170
2311
  readonly get: (number: number) => Effect.Effect<IssueInfo, GitHubError, Repo>;
2312
+ /**
2313
+ * List issues, paginated. `state` is omitted from the request when unset, so GitHub's default applies.
2314
+ *
2315
+ * @remarks
2316
+ * GitHub's issues endpoint also returns pull requests; this does not filter them out.
2317
+ */
2171
2318
  readonly list: (options?: {
2172
2319
  readonly state?: "open" | "closed" | "all" | undefined;
2173
2320
  readonly labels?: ReadonlyArray<string> | undefined;
2174
2321
  readonly page?: PageOptions | undefined;
2175
2322
  }) => Effect.Effect<ReadonlyArray<IssueInfo>, GitHubError, Repo>;
2323
+ /** Close an issue. `reason` is sent as `state_reason` when given; unset, GitHub chooses. */
2176
2324
  readonly close: (number: number, reason?: "completed" | "not_planned") => Effect.Effect<void, GitHubError, Repo>;
2177
- /** Post a comment. */
2325
+ /** Post a comment and return its id. */
2178
2326
  readonly comment: (number: number, body: string) => Effect.Effect<number, GitHubError, Repo>;
2179
2327
  /**
2180
2328
  * Post a marked comment once: create it, or skip if it already exists.
@@ -2204,10 +2352,10 @@ interface GitHubIssueShape {
2204
2352
  * Has `prNumber` already been cross-referenced on this issue?
2205
2353
  *
2206
2354
  * @remarks
2207
- * The idempotence guard one consumer wrote a bespoke timeline query for,
2208
- * so that re-running a workflow does not comment twice.
2355
+ * An idempotence guard over the issue's timeline, so that re-running a
2356
+ * workflow does not comment twice.
2209
2357
  *
2210
- * Two hazards before building on it (effected#306):
2358
+ * Two hazards before building on it:
2211
2359
  *
2212
2360
  * - **An issue obtained from `linkedIssues(pr)` answers `true` from the
2213
2361
  * outset** — the closing link itself puts a cross-reference on the
@@ -2224,11 +2372,30 @@ interface GitHubIssueShape {
2224
2372
  }
2225
2373
  declare const GitHubIssue_base: Context.ServiceClass<GitHubIssue, "@effected/github/GitHubIssue", GitHubIssueShape>;
2226
2374
  /**
2227
- * Issues.
2375
+ * Read, list, close and comment on issues, and resolve the issues a pull
2376
+ * request closes.
2377
+ *
2378
+ * @remarks
2379
+ * Provide it with {@link GitHubIssue.layer}, which needs a `GitHubClient`; each
2380
+ * method also needs a `Repo` in `R`.
2381
+ *
2382
+ * @example
2383
+ * ```ts
2384
+ * import { GitHubIssue } from "@effected/github";
2385
+ * import { Effect } from "effect";
2386
+ *
2387
+ * const closeWontFix = (number: number) =>
2388
+ * Effect.gen(function* () {
2389
+ * const issues = yield* GitHubIssue;
2390
+ * yield* issues.comment(number, "Closing as not planned.");
2391
+ * yield* issues.close(number, "not_planned");
2392
+ * });
2393
+ * ```
2228
2394
  *
2229
2395
  * @public
2230
2396
  */
2231
2397
  export declare class GitHubIssue extends GitHubIssue_base {
2398
+ /** The live service, built over a `GitHubClient`. */
2232
2399
  static readonly layer: Layer.Layer<GitHubIssue, never, GitHubClient>;
2233
2400
  /** An in-memory double; unstubbed members die naming themselves. */
2234
2401
  static readonly makeTest: (overrides?: Partial<GitHubIssueShape>) => GitHubIssueShape;
@@ -2250,7 +2417,7 @@ declare const ReleaseInfo_base: Schema.Class<ReleaseInfo, Schema.Struct<{
2250
2417
  readonly uploadUrl: Schema.String;
2251
2418
  }>, {}>;
2252
2419
  /**
2253
- * A release.
2420
+ * A release, projected to the fields callers read.
2254
2421
  *
2255
2422
  * @public
2256
2423
  */
@@ -2270,11 +2437,12 @@ declare const ReleaseAsset_base: Schema.Class<ReleaseAsset, Schema.Struct<{
2270
2437
  */
2271
2438
  export declare class ReleaseAsset extends ReleaseAsset_base {}
2272
2439
  /**
2273
- * Releases and their assets.
2440
+ * Create, read, list and update releases, and upload and list their assets.
2274
2441
  *
2275
2442
  * @public
2276
2443
  */
2277
2444
  interface GitHubReleaseShape {
2445
+ /** Create a release for `tag`. Unset fields are left to GitHub's defaults. */
2278
2446
  readonly create: (input: {
2279
2447
  readonly tag: string;
2280
2448
  readonly name?: string | undefined;
@@ -2283,12 +2451,15 @@ interface GitHubReleaseShape {
2283
2451
  readonly prerelease?: boolean | undefined;
2284
2452
  readonly generateReleaseNotes?: boolean | undefined;
2285
2453
  }) => Effect.Effect<ReleaseInfo, GitHubError, Repo>;
2454
+ /** Read the release for `tag`. Fails `notFound` when there is none. */
2286
2455
  readonly getByTag: (tag: string) => Effect.Effect<ReleaseInfo, GitHubError, Repo>;
2287
2456
  /** As {@link GitHubReleaseShape.getByTag}, with absence as `Option.none`. */
2288
2457
  readonly getByTagOption: (tag: string) => Effect.Effect<Option.Option<ReleaseInfo>, GitHubError, Repo>;
2458
+ /** List releases, paginated. */
2289
2459
  readonly list: (options?: {
2290
2460
  readonly page?: PageOptions | undefined;
2291
2461
  }) => Effect.Effect<ReadonlyArray<ReleaseInfo>, GitHubError, Repo>;
2462
+ /** Patch a release by id; only the fields given are sent. */
2292
2463
  readonly update: (id: number, patch: {
2293
2464
  readonly name?: string | undefined;
2294
2465
  readonly body?: string | undefined;
@@ -2317,17 +2488,36 @@ interface GitHubReleaseShape {
2317
2488
  readonly contentType: string;
2318
2489
  readonly label?: string | undefined;
2319
2490
  }) => Effect.Effect<ReleaseAsset, GitHubError, Repo>;
2491
+ /** List a release's assets, paginated. */
2320
2492
  readonly listAssets: (id: number, options?: {
2321
2493
  readonly page?: PageOptions | undefined;
2322
2494
  }) => Effect.Effect<ReadonlyArray<ReleaseAsset>, GitHubError, Repo>;
2323
2495
  }
2324
2496
  declare const GitHubRelease_base: Context.ServiceClass<GitHubRelease, "@effected/github/GitHubRelease", GitHubReleaseShape>;
2325
2497
  /**
2326
- * Releases.
2498
+ * Create, read, list and update GitHub releases, and upload and list their
2499
+ * assets.
2500
+ *
2501
+ * @remarks
2502
+ * Provide it with {@link GitHubRelease.layer}, which needs a `GitHubClient`;
2503
+ * each method also needs a `Repo` in `R`.
2504
+ *
2505
+ * @example
2506
+ * ```ts
2507
+ * import { GitHubRelease } from "@effected/github";
2508
+ * import { Effect } from "effect";
2509
+ *
2510
+ * const publish = Effect.gen(function* () {
2511
+ * const releases = yield* GitHubRelease;
2512
+ * const release = yield* releases.create({ tag: "v1.2.3", generateReleaseNotes: true });
2513
+ * return release.url;
2514
+ * });
2515
+ * ```
2327
2516
  *
2328
2517
  * @public
2329
2518
  */
2330
2519
  export declare class GitHubRelease extends GitHubRelease_base {
2520
+ /** The live service, built over a `GitHubClient`. */
2331
2521
  static readonly layer: Layer.Layer<GitHubRelease, never, GitHubClient>;
2332
2522
  /** An in-memory double; unstubbed members die naming themselves. */
2333
2523
  static readonly makeTest: (overrides?: Partial<GitHubReleaseShape>) => GitHubReleaseShape;
@@ -2340,11 +2530,9 @@ export declare class GitHubRelease extends GitHubRelease_base {
2340
2530
  * Everything GitHub reports about a repository.
2341
2531
  *
2342
2532
  * @remarks
2343
- * The **generated** response type, not a hand-written projection. One surveyed
2344
- * consumer declared a sixteen-field interface for this endpoint and round-tripped
2345
- * those fields back through `PATCH` — and every one of the sixteen already
2346
- * existed, verbatim, in the OpenAPI types the package now leans on. Re-declaring
2347
- * them would have been the same mistake with our name on it.
2533
+ * The **generated** response type for `GET /repos/{owner}/{repo}`, not a
2534
+ * hand-written projection, so every field GitHub documents is available with
2535
+ * its documented type.
2348
2536
  *
2349
2537
  * @public
2350
2538
  */
@@ -2363,10 +2551,9 @@ type RepositoryPatch = Omit<Params<"PATCH /repos/{owner}/{repo}">, "owner" | "re
2363
2551
  * The shape you actually have when you are applying only what a user
2364
2552
  * configured. Octokit's generated params spell an optional field as
2365
2553
  * `has_issues?: boolean`, **not** `has_issues?: boolean | undefined`, so under
2366
- * `exactOptionalPropertyTypes` — on in this repo and in the silk tsconfig base
2367
- * — a `Partial<T>` built from your own settings schema does not assign to
2368
- * `RepositoryPatch` at all. This type does, and {@link repositoryPatch} turns
2369
- * it into one.
2554
+ * `exactOptionalPropertyTypes` a `Partial<T>` built from your own settings
2555
+ * schema does not assign to `RepositoryPatch` at all. This type does, and
2556
+ * {@link repositoryPatch} turns it into one.
2370
2557
  *
2371
2558
  * @public
2372
2559
  */
@@ -2377,10 +2564,7 @@ type RepositoryPatchDraft = { readonly [K in keyof RepositoryPatch]?: Repository
2377
2564
  *
2378
2565
  * @remarks
2379
2566
  * The supported spelling for "apply only what was configured" — the natural
2380
- * shape for a sync action, and the one the checker cannot follow on its own.
2381
- * Without it a consumer under the recommended tsconfig is quietly pushed toward
2382
- * `as`, which is a real cost in a package whose stated design property is that
2383
- * the route is the key and there are no casts.
2567
+ * shape for a sync action, without a cast at the call site.
2384
2568
  *
2385
2569
  * Dropping the key rather than sending `undefined` is what the wire needs:
2386
2570
  * `PATCH` treats an absent field as "leave it alone", while an explicit `null`
@@ -2433,12 +2617,9 @@ export declare const SECURITY_ANALYSIS_STATUS_FIELDS: ReadonlySet<string>;
2433
2617
  * `PATCH /repos/{owner}/{repo}` route accepts none of them, and
2434
2618
  * `has_discussions` is the treacherous one: the REST **read** returns it, so
2435
2619
  * routing its write to the PATCH looks symmetric, but the PATCH silently
2436
- * ignores unknown body fields and answers 200 — reported as applied on every
2437
- * run while the repository never changed (effected#358). Setting any of these
2438
- * forces a second round trip to learn the repository's node id.
2439
- *
2440
- * Field names verified against `UpdateRepositoryInput` by live introspection,
2441
- * 2026-08-15.
2620
+ * ignores unknown body fields and answers 200, so the write would look applied
2621
+ * while the repository never changed. Setting any of these forces a second
2622
+ * round trip to learn the repository's node id.
2442
2623
  *
2443
2624
  * @public
2444
2625
  */
@@ -2490,7 +2671,8 @@ interface AppliedSettings {
2490
2671
  readonly graphql: ReadonlyArray<string>;
2491
2672
  }
2492
2673
  /**
2493
- * The repository itself.
2674
+ * Read and update a repository's settings, and look up its default branch, node
2675
+ * id and owner type.
2494
2676
  *
2495
2677
  * @public
2496
2678
  */
@@ -2503,8 +2685,7 @@ interface GitHubRepositoryShape {
2503
2685
  * The default branch's name.
2504
2686
  *
2505
2687
  * @remarks
2506
- * One surveyed consumer spent eight lines of hand-written octokit interface
2507
- * plus eleven lines of code to read this one string.
2688
+ * Reads the repository payload and returns `default_branch`.
2508
2689
  */
2509
2690
  readonly defaultBranch: Effect.Effect<string, GitHubError, Repo>;
2510
2691
  /**
@@ -2512,7 +2693,7 @@ interface GitHubRepositoryShape {
2512
2693
  *
2513
2694
  * @remarks
2514
2695
  * Needed as `repositoryId` by the `createLinkedBranch` and `createPullRequest`
2515
- * mutations, which is why a second consumer cast `repos.get` for it alone.
2696
+ * mutations.
2516
2697
  */
2517
2698
  readonly nodeId: Effect.Effect<string, GitHubError, Repo>;
2518
2699
  /**
@@ -2536,13 +2717,14 @@ interface GitHubRepositoryShape {
2536
2717
  * @remarks
2537
2718
  * `updateSettings` is the thin, faithfully-typed PATCH and returns what
2538
2719
  * GitHub then reports. This is the **applicator**: it takes an open map,
2539
- * routes each key to whichever API can actually set it, and returns nothing.
2720
+ * routes each key to whichever API can actually set it, and returns an
2721
+ * {@link AppliedSettings} naming the keys that were sent through each.
2540
2722
  *
2541
- * Two settings — `has_sponsorships` and `has_pull_requests` — have never
2542
- * existed on the REST endpoint and are only reachable through GraphQL's
2543
- * `updateRepository`, which addresses a repository by **node id**. So a map
2544
- * touching either costs an extra read; a map touching neither does not, which
2545
- * is the common case.
2723
+ * Three settings — `has_sponsorships`, `has_pull_requests` and
2724
+ * `has_discussions` ({@link GRAPHQL_ONLY_SETTINGS}) — are only reachable
2725
+ * through GraphQL's `updateRepository`, which addresses a repository by **node
2726
+ * id**. So a map touching any of them costs an extra read; a map touching none
2727
+ * does not, which is the common case.
2546
2728
  *
2547
2729
  * The map is open by design. GitHub's settings surface is large and moving,
2548
2730
  * and a closed type here would date the package — but it also means a typo is
@@ -2553,11 +2735,31 @@ interface GitHubRepositoryShape {
2553
2735
  }
2554
2736
  declare const GitHubRepository_base: Context.ServiceClass<GitHubRepository, "@effected/github/GitHubRepository", GitHubRepositoryShape>;
2555
2737
  /**
2556
- * Repository settings and coordinates.
2738
+ * Read and update a repository's settings, including settings only GraphQL can
2739
+ * write, and look up its default branch, node id and owner type.
2740
+ *
2741
+ * @remarks
2742
+ * Provide it with {@link GitHubRepository.layer}, which needs a `GitHubClient`;
2743
+ * every member also needs a `Repo` in `R`. `settings`, `defaultBranch`, `nodeId`
2744
+ * and `ownerType` are `Effect` values, not functions.
2745
+ *
2746
+ * @example
2747
+ * ```ts
2748
+ * import { GitHubRepository } from "@effected/github";
2749
+ * import { Effect } from "effect";
2750
+ *
2751
+ * const program = Effect.gen(function* () {
2752
+ * const repository = yield* GitHubRepository;
2753
+ * const branch = yield* repository.defaultBranch;
2754
+ * const applied = yield* repository.applySettings({ has_wiki: false, has_discussions: true });
2755
+ * return { branch, applied }; // applied.rest, applied.graphql
2756
+ * });
2757
+ * ```
2557
2758
  *
2558
2759
  * @public
2559
2760
  */
2560
2761
  export declare class GitHubRepository extends GitHubRepository_base {
2762
+ /** The live service, built over a `GitHubClient`. */
2561
2763
  static readonly layer: Layer.Layer<GitHubRepository, never, GitHubClient>;
2562
2764
  /** An in-memory double; unstubbed members die naming themselves. */
2563
2765
  static readonly makeTest: (overrides?: Partial<GitHubRepositoryShape>) => GitHubRepositoryShape;
@@ -2597,7 +2799,7 @@ export declare class SemverTag extends SemverTag_base {}
2597
2799
  *
2598
2800
  * @remarks
2599
2801
  * The default covers the three shapes `@effected/workspaces`' `ReleaseTag`
2600
- * produces and the surveyed repos actually cut: `v1.2.3`, `pkg@v1.2.3` and
2802
+ * produces: `v1.2.3`, `pkg@v1.2.3` and
2601
2803
  * `@scope/pkg@1.2.3`. Taking the substring after the **last** `@` is what makes
2602
2804
  * the scoped form work, since the scope itself contains one.
2603
2805
  *
@@ -2633,7 +2835,7 @@ interface GitTagShape {
2633
2835
  readonly upsert: (tag: string, sha: string) => Effect.Effect<void, GitHubError, Repo>;
2634
2836
  /** Delete the tag ref. */
2635
2837
  readonly delete: (tag: string) => Effect.Effect<void, GitHubError, Repo>;
2636
- /** Every tag, newest GitHub-order first. `prefix` filters client-side. */
2838
+ /** Every tag, in GitHub's order. `prefix` filters client-side. */
2637
2839
  readonly list: (options?: {
2638
2840
  readonly prefix?: string | undefined;
2639
2841
  readonly page?: PageOptions | undefined;
@@ -2649,10 +2851,9 @@ interface GitTagShape {
2649
2851
  * The newest version-shaped tag.
2650
2852
  *
2651
2853
  * @remarks
2652
- * Replaces thirty-five lines at one surveyed call site that ran **one
2653
- * `Effect.result` per parse and another per comparison** to answer this. Both
2654
- * are synchronous in `@effected/semver` (`parseResult`, `compare`), so this is
2655
- * a single pass over the page stream with no round trips at all.
2854
+ * Parsing and comparison are both synchronous in `@effected/semver`
2855
+ * (`parseResult`, `compare`), so this is a single pass over the page stream
2856
+ * with no extra round trips.
2656
2857
  *
2657
2858
  * **"Newest" means highest version, not most recent.** That is the right
2658
2859
  * answer for a single-versioned repository and the wrong instrument for a
@@ -2660,8 +2861,7 @@ interface GitTagShape {
2660
2861
  * ordering and recency are unrelated: a `pkg-a@2.0.0` tag outranks a
2661
2862
  * `pkg-b@1.4.0` cut yesterday, so the result can sit several releases behind
2662
2863
  * the actual head and never move. Nothing about the failure is visible —
2663
- * a stale-but-plausible tag comes back, and one consumer pinned its release
2664
- * boundary two releases back, permanently. In a monorepo, filter by the
2864
+ * a stale-but-plausible tag comes back. In a monorepo, filter by the
2665
2865
  * package's tag prefix (see {@link LatestSemverOptions}) so the comparison
2666
2866
  * runs within one version line, or order by tagged-commit date instead.
2667
2867
  */
@@ -2669,11 +2869,29 @@ interface GitTagShape {
2669
2869
  }
2670
2870
  declare const GitTag_base: Context.ServiceClass<GitTag, "@effected/github/GitTag", GitTagShape>;
2671
2871
  /**
2672
- * Tags.
2872
+ * Create, move, resolve, list and delete tag refs through GitHub's Git Database
2873
+ * API, and find the newest version-shaped tag.
2874
+ *
2875
+ * @remarks
2876
+ * Provide it with {@link GitTag.layer}, which needs a `GitHubClient`; each
2877
+ * method also needs a `Repo` in `R`.
2878
+ *
2879
+ * @example
2880
+ * ```ts
2881
+ * import { GitTag } from "@effected/github";
2882
+ * import { Effect, Option } from "effect";
2883
+ *
2884
+ * const latest = Effect.gen(function* () {
2885
+ * const tags = yield* GitTag;
2886
+ * const newest = yield* tags.latestSemver({ prefix: "v" });
2887
+ * return Option.map(newest, (tag) => tag.version.toString());
2888
+ * });
2889
+ * ```
2673
2890
  *
2674
2891
  * @public
2675
2892
  */
2676
2893
  export declare class GitTag extends GitTag_base {
2894
+ /** The live service, built over a `GitHubClient`. */
2677
2895
  static readonly layer: Layer.Layer<GitTag, never, GitHubClient>;
2678
2896
  /** An in-memory double; unstubbed members die naming themselves. */
2679
2897
  static readonly makeTest: (overrides?: Partial<GitTagShape>) => GitTagShape;
@@ -2722,28 +2940,32 @@ declare const PullRequestInfo_base: Schema.Class<PullRequestInfo, Schema.Struct<
2722
2940
  *
2723
2941
  * @remarks
2724
2942
  * This is the **domain** shape, and the only pull-request type this package
2725
- * exports. The wire shape GitHub actually answers with is the private
2726
- * `RawPull` interface further down this module, and the two are deliberately
2727
- * different: `RawPull` nests `head`/`base` as `{ ref, sha }` and spells the
2728
- * link `html_url`, where this class flattens them to `head`/`headSha` and
2729
- * spells it `url`. Reading the wrong one produces code that typechecks against
2730
- * a member set the boundary will never hand it. If you are writing a test
2731
- * double or a fixture, this is the type you build.
2943
+ * exports. It flattens GitHub's nested `head`/`base` objects to
2944
+ * `head`/`headSha` and `base`/`baseSha`, and spells the link `url`. If you are
2945
+ * writing a test double or a fixture, this is the type you build.
2732
2946
  *
2733
2947
  * @public
2734
2948
  */
2735
2949
  export declare class PullRequestInfo extends PullRequestInfo_base {}
2736
- /** What {@link PullRequestShape.upsert} did. @public */
2950
+ /**
2951
+ * What {@link PullRequestShape.upsert} did.
2952
+ *
2953
+ * @public
2954
+ */
2737
2955
  interface UpsertedPullRequest {
2956
+ /** The pull request, as created or as updated. */
2738
2957
  readonly pullRequest: PullRequestInfo;
2958
+ /** `true` when a new pull request was opened, `false` when an open one was updated. */
2739
2959
  readonly created: boolean;
2740
2960
  }
2741
2961
  /**
2742
- * Pull requests.
2962
+ * Read, list, create, update, merge and label pull requests, and control
2963
+ * auto-merge.
2743
2964
  *
2744
2965
  * @public
2745
2966
  */
2746
2967
  interface PullRequestShape {
2968
+ /** Read one pull request. Fails `notFound` when it does not exist. */
2747
2969
  readonly get: (number: number) => Effect.Effect<PullRequestInfo, GitHubError, Repo>;
2748
2970
  /**
2749
2971
  * Open, closed or all pull requests, optionally filtered.
@@ -2752,10 +2974,8 @@ interface PullRequestShape {
2752
2974
  * `head` accepts **either** the qualified `owner:ref` GitHub's filter wants
2753
2975
  * or a bare `ref`, which is qualified with the current repo's owner on the
2754
2976
  * way out. So for a pull request opened **from the current repository**,
2755
- * feeding this method `PullRequestInfo.head` — which is the bare
2756
- * `raw.head.ref` — round-trips correctly, and a consumer filtering the full
2757
- * list client-side because the raw REST route ignores an unqualified ref no
2758
- * longer needs to.
2977
+ * feeding this method `PullRequestInfo.head` (the bare branch name)
2978
+ * round-trips correctly; GitHub's own route ignores an unqualified ref.
2759
2979
  *
2760
2980
  * **The round trip does not hold for a fork-originated pull request.**
2761
2981
  * `PullRequestInfo` projects only the ref and drops the source owner, so
@@ -2777,9 +2997,7 @@ interface PullRequestShape {
2777
2997
  * Each entry is a full {@link CommitFile} — path **and** status, plus the
2778
2998
  * line counts and any pre-rename path — the same projection
2779
2999
  * `GitHubCommit.changedFiles` returns, because GitHub answers both
2780
- * endpoints with the same `diff-entry` shape. An earlier version projected
2781
- * to the path alone, and consumers who needed the status fell back to a raw
2782
- * route.
3000
+ * endpoints with the same `diff-entry` shape.
2783
3001
  */
2784
3002
  readonly listFiles: (number: number, options?: {
2785
3003
  readonly page?: PageOptions | undefined;
@@ -2788,14 +3006,12 @@ interface PullRequestShape {
2788
3006
  * The pull requests associated with a commit.
2789
3007
  *
2790
3008
  * @remarks
2791
- * Named for the question it answers, because the previous surface had this
2792
- * method and one consumer never found it — dropping to a raw octokit callback
2793
- * with the only `noExplicitAny` suppression in the entire survey. It also
2794
- * paginates now, which the previous one did not.
3009
+ * Paginated: pass `page` to bound the walk.
2795
3010
  */
2796
3011
  readonly listAssociatedWithCommit: (sha: string, options?: {
2797
3012
  readonly page?: PageOptions | undefined;
2798
3013
  }) => Effect.Effect<ReadonlyArray<PullRequestInfo>, GitHubError, Repo>;
3014
+ /** Open a pull request from `head` into `base`. */
2799
3015
  readonly create: (input: {
2800
3016
  readonly title: string;
2801
3017
  readonly head: string;
@@ -2803,13 +3019,20 @@ interface PullRequestShape {
2803
3019
  readonly body?: string | undefined;
2804
3020
  readonly draft?: boolean | undefined;
2805
3021
  }) => Effect.Effect<PullRequestInfo, GitHubError, Repo>;
3022
+ /** Patch a pull request; only the fields given are sent. */
2806
3023
  readonly update: (number: number, patch: {
2807
3024
  readonly title?: string | undefined;
2808
3025
  readonly body?: string | undefined;
2809
3026
  readonly state?: "open" | "closed" | undefined;
2810
3027
  readonly base?: string | undefined;
2811
3028
  }) => Effect.Effect<PullRequestInfo, GitHubError, Repo>;
2812
- /** Update the open pull request for `head`→`base`, or open one. */
3029
+ /**
3030
+ * Update the open pull request for `head`→`base`, or open one.
3031
+ *
3032
+ * @remarks
3033
+ * When a pull request is already open, only `title` and `body` are updated;
3034
+ * `draft` applies only when a new pull request is opened.
3035
+ */
2813
3036
  readonly upsert: (input: {
2814
3037
  readonly title: string;
2815
3038
  readonly head: string;
@@ -2817,12 +3040,15 @@ interface PullRequestShape {
2817
3040
  readonly body?: string | undefined;
2818
3041
  readonly draft?: boolean | undefined;
2819
3042
  }) => Effect.Effect<UpsertedPullRequest, GitHubError, Repo>;
3043
+ /** Merge a pull request and return the merge commit sha. `method` defaults to GitHub's choice. */
2820
3044
  readonly merge: (number: number, options?: {
2821
3045
  readonly method?: "merge" | "squash" | "rebase" | undefined;
2822
3046
  readonly commitTitle?: string | undefined;
2823
3047
  readonly commitMessage?: string | undefined;
2824
3048
  }) => Effect.Effect<string, GitHubError, Repo>;
3049
+ /** Add labels to a pull request (as an issue), keeping the ones already there. */
2825
3050
  readonly addLabels: (number: number, labels: ReadonlyArray<string>) => Effect.Effect<void, GitHubError, Repo>;
3051
+ /** Request reviews from users and/or teams (team slugs). */
2826
3052
  readonly requestReviewers: (number: number, reviewers: {
2827
3053
  readonly users?: ReadonlyArray<string> | undefined;
2828
3054
  readonly teams?: ReadonlyArray<string> | undefined;
@@ -2831,20 +3057,42 @@ interface PullRequestShape {
2831
3057
  * Turn auto-merge on or off.
2832
3058
  *
2833
3059
  * @remarks
2834
- * An explicit call, not an option on `create`/`update`. The previous surface
2835
- * fired these mutations from an `Effect.tap` **after** the create succeeded,
2836
- * so a create that worked could still surface an auto-merge failure as if the
2837
- * create had failed.
3060
+ * An explicit call, not an option on `create`/`update`, so a create that
3061
+ * worked is never reported as failed because auto-merge was refused. Pass
3062
+ * `"off"` to disable it.
2838
3063
  */
2839
3064
  readonly setAutoMerge: (pullRequest: PullRequestInfo, method: "merge" | "squash" | "rebase" | "off") => Effect.Effect<void, GitHubGraphQLError, Repo>;
2840
3065
  }
2841
3066
  declare const PullRequest_base: Context.ServiceClass<PullRequest, "@effected/github/PullRequest", PullRequestShape>;
2842
3067
  /**
2843
- * Pull requests.
3068
+ * Read, list, create, update, merge and label pull requests, and control
3069
+ * auto-merge.
3070
+ *
3071
+ * @remarks
3072
+ * Provide it with {@link PullRequest.layer}, which needs a `GitHubClient`; each
3073
+ * method also needs a `Repo` in `R`.
3074
+ *
3075
+ * @example
3076
+ * ```ts
3077
+ * import { PullRequest } from "@effected/github";
3078
+ * import { Effect } from "effect";
3079
+ *
3080
+ * const openOrUpdate = Effect.gen(function* () {
3081
+ * const pulls = yield* PullRequest;
3082
+ * const { pullRequest, created } = yield* pulls.upsert({
3083
+ * title: "chore: release",
3084
+ * head: "changeset-release/main",
3085
+ * base: "main",
3086
+ * });
3087
+ * yield* pulls.setAutoMerge(pullRequest, "squash");
3088
+ * return created;
3089
+ * });
3090
+ * ```
2844
3091
  *
2845
3092
  * @public
2846
3093
  */
2847
3094
  export declare class PullRequest extends PullRequest_base {
3095
+ /** The live service, built over a `GitHubClient`. */
2848
3096
  static readonly layer: Layer.Layer<PullRequest, never, GitHubClient>;
2849
3097
  /** An in-memory double; unstubbed members die naming themselves. */
2850
3098
  static readonly makeTest: (overrides?: Partial<PullRequestShape>) => PullRequestShape;
@@ -2875,10 +3123,12 @@ type SecretScope = "actions" | "dependabot" | "codespaces";
2875
3123
  * @public
2876
3124
  */
2877
3125
  interface SecretInfo {
3126
+ /** The secret's name. */
2878
3127
  readonly name: string;
2879
3128
  }
2880
3129
  /**
2881
- * Repository and environment secrets.
3130
+ * Write, list and delete Actions, Dependabot and Codespaces secrets on a
3131
+ * repository, and Actions secrets on its environments.
2882
3132
  *
2883
3133
  * @public
2884
3134
  */
@@ -2898,7 +3148,8 @@ interface RepositorySecretShape {
2898
3148
  }
2899
3149
  declare const RepositorySecret_base: Context.ServiceClass<RepositorySecret, "@effected/github/RepositorySecret", RepositorySecretShape>;
2900
3150
  /**
2901
- * Secrets, encrypted client-side before they leave the process.
3151
+ * Write, list and delete repository and environment secrets, encrypted
3152
+ * client-side before they leave the process.
2902
3153
  *
2903
3154
  * @remarks
2904
3155
  * Every write is a **two-step**: fetch the store's public key, then `PUT` a
@@ -2914,10 +3165,27 @@ declare const RepositorySecret_base: Context.ServiceClass<RepositorySecret, "@ef
2914
3165
  * the type; this module performs the single `Redacted.value` unwrap, at the
2915
3166
  * moment of encryption, and the sealed box is what continues.
2916
3167
  *
3168
+ * Provide it with {@link RepositorySecret.layer}, which needs a `GitHubClient`;
3169
+ * each method also needs a `Repo` in `R`.
3170
+ *
3171
+ * @example
3172
+ * ```ts
3173
+ * import { RepositorySecret } from "@effected/github";
3174
+ * import { Effect, Redacted } from "effect";
3175
+ *
3176
+ * const program = Effect.gen(function* () {
3177
+ * const secrets = yield* RepositorySecret;
3178
+ * yield* secrets.set("NPM_TOKEN", Redacted.make("npm_example"), "actions");
3179
+ * return yield* secrets.list("actions"); // names only; values are never returned
3180
+ * });
3181
+ * ```
3182
+ *
2917
3183
  * @public
2918
3184
  */
2919
3185
  export declare class RepositorySecret extends RepositorySecret_base {
2920
3186
  /**
3187
+ * The live service, built over a `GitHubClient`.
3188
+ *
2921
3189
  * @remarks
2922
3190
  * `(client) => make(client)` rather than `make`: a static initializer runs
2923
3191
  * while the module body is still evaluating, so naming a `const` declared
@@ -2932,7 +3200,9 @@ export declare class RepositorySecret extends RepositorySecret_base {
2932
3200
  //#endregion
2933
3201
  //#region src/RepositorySecurity.d.ts
2934
3202
  /**
2935
- * The three repository security features that have their own endpoints.
3203
+ * Read and toggle the three repository security features that have their own
3204
+ * endpoints: Dependabot alerts, Dependabot security fixes and private
3205
+ * vulnerability reporting.
2936
3206
  *
2937
3207
  * @public
2938
3208
  */
@@ -2952,7 +3222,8 @@ interface RepositorySecurityShape {
2952
3222
  }
2953
3223
  declare const RepositorySecurity_base: Context.ServiceClass<RepositorySecurity, "@effected/github/RepositorySecurity", RepositorySecurityShape>;
2954
3224
  /**
2955
- * Repository security features with dedicated endpoints.
3225
+ * Read and toggle Dependabot alerts, Dependabot security fixes and private
3226
+ * vulnerability reporting.
2956
3227
  *
2957
3228
  * @remarks
2958
3229
  * These are **not** `security_and_analysis` fields and cannot ride along on the
@@ -2975,10 +3246,28 @@ declare const RepositorySecurity_base: Context.ServiceClass<RepositorySecurity,
2975
3246
  * every other failure still fails. A 404 from the other two is a real failure
2976
3247
  * and stays one, which is why the mapping is not applied uniformly.
2977
3248
  *
3249
+ * Provide it with {@link RepositorySecurity.layer}, which needs a
3250
+ * `GitHubClient`; each method also needs a `Repo` in `R`.
3251
+ *
3252
+ * @example
3253
+ * ```ts
3254
+ * import { RepositorySecurity } from "@effected/github";
3255
+ * import { Effect } from "effect";
3256
+ *
3257
+ * const harden = Effect.gen(function* () {
3258
+ * const security = yield* RepositorySecurity;
3259
+ * yield* security.setVulnerabilityAlerts(true);
3260
+ * yield* security.setPrivateVulnerabilityReporting(true);
3261
+ * return yield* security.vulnerabilityAlerts(); // true
3262
+ * });
3263
+ * ```
3264
+ *
2978
3265
  * @public
2979
3266
  */
2980
3267
  export declare class RepositorySecurity extends RepositorySecurity_base {
2981
3268
  /**
3269
+ * The live service, built over a `GitHubClient`.
3270
+ *
2982
3271
  * @remarks
2983
3272
  * `(client) => make(client)` rather than `make`: a static initializer runs
2984
3273
  * while the module body is still evaluating, so naming a `const` declared
@@ -2993,7 +3282,7 @@ export declare class RepositorySecurity extends RepositorySecurity_base {
2993
3282
  //#endregion
2994
3283
  //#region src/RepositoryVariable.d.ts
2995
3284
  /**
2996
- * A variable, as listing returns it.
3285
+ * A variable's name and value, as listing returns it.
2997
3286
  *
2998
3287
  * @remarks
2999
3288
  * Unlike a secret this carries its **value**: variables are readable, so a
@@ -3004,11 +3293,14 @@ export declare class RepositorySecurity extends RepositorySecurity_base {
3004
3293
  * @public
3005
3294
  */
3006
3295
  interface VariableInfo {
3296
+ /** The variable's name. */
3007
3297
  readonly name: string;
3298
+ /** The variable's current value. */
3008
3299
  readonly value: string;
3009
3300
  }
3010
3301
  /**
3011
- * Repository and environment variables.
3302
+ * Create or update, list and delete Actions variables on a repository and on
3303
+ * its environments.
3012
3304
  *
3013
3305
  * @public
3014
3306
  */
@@ -3029,9 +3321,7 @@ interface RepositoryVariableShape {
3029
3321
  * treating any error as absence would turn a permissions problem into a
3030
3322
  * spurious create.
3031
3323
  *
3032
- * **The 404-for-absent behaviour is documented, not probed.** Neither this
3033
- * suite nor the first consumer's has issued this read against real GitHub —
3034
- * both run against doubles.
3324
+ * The 404-for-absent behaviour is GitHub's documented contract.
3035
3325
  *
3036
3326
  * Only `notFound` selects the create branch: a successful read selects the
3037
3327
  * update branch, and any other failure propagates rather than being guessed
@@ -3055,7 +3345,8 @@ interface RepositoryVariableShape {
3055
3345
  }
3056
3346
  declare const RepositoryVariable_base: Context.ServiceClass<RepositoryVariable, "@effected/github/RepositoryVariable", RepositoryVariableShape>;
3057
3347
  /**
3058
- * Repository and environment variables.
3348
+ * Create or update, list and delete Actions variables on a repository and on
3349
+ * its environments.
3059
3350
  *
3060
3351
  * @remarks
3061
3352
  * No encryption and no public key, unlike secrets — but also **no upsert**,
@@ -3063,10 +3354,27 @@ declare const RepositoryVariable_base: Context.ServiceClass<RepositoryVariable,
3063
3354
  * the create and update routes are different endpoints with different verbs and
3064
3355
  * neither tolerates the other's case.
3065
3356
  *
3357
+ * Provide it with {@link RepositoryVariable.layer}, which needs a
3358
+ * `GitHubClient`; each method also needs a `Repo` in `R`.
3359
+ *
3360
+ * @example
3361
+ * ```ts
3362
+ * import { RepositoryVariable } from "@effected/github";
3363
+ * import { Effect } from "effect";
3364
+ *
3365
+ * const program = Effect.gen(function* () {
3366
+ * const variables = yield* RepositoryVariable;
3367
+ * yield* variables.set("DEPLOY_REGION", "eu-west-1"); // creates or updates
3368
+ * return yield* variables.list();
3369
+ * });
3370
+ * ```
3371
+ *
3066
3372
  * @public
3067
3373
  */
3068
3374
  export declare class RepositoryVariable extends RepositoryVariable_base {
3069
3375
  /**
3376
+ * The live service, built over a `GitHubClient`.
3377
+ *
3070
3378
  * @remarks
3071
3379
  * `(client) => make(client)` rather than `make`: a static initializer runs
3072
3380
  * while the module body is still evaluating, so naming a `const` declared
@@ -3092,7 +3400,9 @@ export declare class RepositoryVariable extends RepositoryVariable_base {
3092
3400
  * @public
3093
3401
  */
3094
3402
  interface RulesetInfo {
3403
+ /** The ruleset's numeric id. */
3095
3404
  readonly id: number;
3405
+ /** The ruleset's name. */
3096
3406
  readonly name: string;
3097
3407
  /** `"Repository"` for the repository's own, `"Organization"` for an inherited one. */
3098
3408
  readonly source_type?: string | undefined;
@@ -3108,15 +3418,22 @@ interface RulesetInfo {
3108
3418
  * @public
3109
3419
  */
3110
3420
  interface RulesetPayload {
3421
+ /** The ruleset's name, which `upsert` matches on. */
3111
3422
  readonly name: string;
3423
+ /** What it applies to: `"branch"`, `"tag"` or `"push"`. */
3112
3424
  readonly target: string;
3425
+ /** `"active"`, `"evaluate"` or `"disabled"`. */
3113
3426
  readonly enforcement: string;
3427
+ /** Which refs it applies to. Passed to GitHub as given. */
3114
3428
  readonly conditions?: unknown;
3429
+ /** The rules it enforces. Passed to GitHub as given. */
3115
3430
  readonly rules?: unknown;
3431
+ /** Actors allowed to bypass it. Passed to GitHub as given. */
3116
3432
  readonly bypass_actors?: unknown;
3117
3433
  }
3118
3434
  /**
3119
- * Repository rulesets, and the lookups their bypass actors need.
3435
+ * Create or update, list and delete repository rulesets, and look up the team
3436
+ * and role ids their bypass actors need.
3120
3437
  *
3121
3438
  * @public
3122
3439
  */
@@ -3149,7 +3466,8 @@ interface RulesetShape {
3149
3466
  }
3150
3467
  declare const Ruleset_base: Context.ServiceClass<Ruleset, "@effected/github/Ruleset", RulesetShape>;
3151
3468
  /**
3152
- * Repository rulesets.
3469
+ * Create or update, list and delete repository rulesets, and look up the team
3470
+ * and role ids their bypass actors need.
3153
3471
  *
3154
3472
  * @remarks
3155
3473
  * ## An inherited ruleset is never written to
@@ -3161,14 +3479,34 @@ declare const Ruleset_base: Context.ServiceClass<Ruleset, "@effected/github/Rule
3161
3479
  * that never mentioned the organization.
3162
3480
  *
3163
3481
  * {@link RulesetShape.upsert} filters on `source_type` before matching, so an
3164
- * inherited ruleset can never be the target of a write. This arrived as a fix
3165
- * for a live defect in the consumer this module was ported from, where the
3166
- * filter was absent.
3482
+ * inherited ruleset can never be the target of a write.
3483
+ *
3484
+ * Provide it with {@link Ruleset.layer}, which needs a `GitHubClient`; each
3485
+ * method also needs a `Repo` in `R`.
3486
+ *
3487
+ * @example
3488
+ * ```ts
3489
+ * import { Ruleset } from "@effected/github";
3490
+ * import { Effect } from "effect";
3491
+ *
3492
+ * const protectMain = Effect.gen(function* () {
3493
+ * const rulesets = yield* Ruleset;
3494
+ * yield* rulesets.upsert({
3495
+ * name: "protect-main",
3496
+ * target: "branch",
3497
+ * enforcement: "active",
3498
+ * conditions: { ref_name: { include: ["~DEFAULT_BRANCH"], exclude: [] } },
3499
+ * rules: [{ type: "deletion" }],
3500
+ * });
3501
+ * });
3502
+ * ```
3167
3503
  *
3168
3504
  * @public
3169
3505
  */
3170
3506
  export declare class Ruleset extends Ruleset_base {
3171
3507
  /**
3508
+ * The live service, built over a `GitHubClient`.
3509
+ *
3172
3510
  * @remarks
3173
3511
  * `(client) => make(client)` rather than `make`: a static initializer runs
3174
3512
  * while the module body is still evaluating, so naming a `const` declared
@@ -3205,7 +3543,9 @@ declare const PermissionGap_base: Schema.Class<PermissionGap, Schema.Struct<{
3205
3543
  */
3206
3544
  export declare class PermissionGap extends PermissionGap_base {}
3207
3545
  declare const ExtraPermission_base: Schema.Class<ExtraPermission, Schema.Struct<{
3546
+ /** The permission's name, e.g. `"contents"`. */
3208
3547
  readonly permission: Schema.String;
3548
+ /** What the token has. */
3209
3549
  readonly granted: Schema.Literals<readonly ["read", "write", "admin"]>;
3210
3550
  /** What was asked for, when anything was. */
3211
3551
  readonly required: Schema.optionalKey<Schema.Literals<readonly ["read", "write", "admin"]>>;
@@ -3255,17 +3595,12 @@ declare const TokenPermissions_base: Schema.Class<TokenPermissions, Schema.Struc
3255
3595
  * The permissions a token was granted, and what they satisfy.
3256
3596
  *
3257
3597
  * @remarks
3258
- * **A pure class, not a service.** The version this replaces was a
3259
- * `Context.Service` whose live layer was a `Layer.succeed` with zero octokit
3260
- * calls and an empty `R` — a `read < write < admin` comparator behind a service
3261
- * boundary that bought nothing. It cost something, though: its test double
3262
- * reimplemented the entire ranking and every assertion branch, making it the
3263
- * heaviest of the thirty-eight doubles in the package.
3264
- *
3265
- * Here there is no service, no layer and no double: a caller holds the
3266
- * permissions GitHub already gave it (`InstallationToken.permissions`) and
3267
- * compares them. The only `Effect`s are the two assertions, and they exist only
3268
- * because failing typed is more useful than returning a boolean.
3598
+ * **A pure class, not a service.** It compares permission levels
3599
+ * (`read < write < admin`), so there is no layer and no test double: a caller
3600
+ * holds the permissions GitHub already gave it (`InstallationToken.permissions`)
3601
+ * and compares them. The only `Effect`s are the two assertions, which fail with
3602
+ * `TokenPermissionError` because failing typed is more useful than returning a
3603
+ * boolean.
3269
3604
  *
3270
3605
  * @example
3271
3606
  * ```ts
@@ -3308,11 +3643,13 @@ export declare class TokenPermissions extends TokenPermissions_base {
3308
3643
  //#endregion
3309
3644
  //#region src/WorkflowDispatch.d.ts
3310
3645
  declare const WorkflowRunStatus_base: Schema.Class<WorkflowRunStatus, Schema.Struct<{
3646
+ /** The run's numeric id. */
3311
3647
  readonly id: Schema.Int;
3312
3648
  /** `queued`, `in_progress`, `completed`, … */
3313
3649
  readonly status: Schema.String;
3314
3650
  /** Set once `status` is `completed`. */
3315
3651
  readonly conclusion: Schema.optionalKey<Schema.String>;
3652
+ /** The run's web URL. */
3316
3653
  readonly url: Schema.String;
3317
3654
  }>, {}>;
3318
3655
  /**
@@ -3331,9 +3668,8 @@ export declare class WorkflowRunStatus extends WorkflowRunStatus_base {
3331
3668
  * `state` is GitHub's own value — `active`, `disabled_manually`,
3332
3669
  * `disabled_inactivity`, and so on. It is reported rather than interpreted:
3333
3670
  * whether a *disabled* workflow counts for a given GitHub feature is that
3334
- * feature's rule, not this package's, and encoding a guess here would put an
3335
- * unverified server-side behaviour in a library that cannot test it. Callers
3336
- * that care filter on it themselves.
3671
+ * feature's rule, not this package's. Callers that care filter on it
3672
+ * themselves.
3337
3673
  *
3338
3674
  * @public
3339
3675
  */
@@ -3348,7 +3684,7 @@ interface WorkflowInfo {
3348
3684
  readonly state: string;
3349
3685
  }
3350
3686
  /**
3351
- * How long to wait for a dispatched run.
3687
+ * How often to poll for a dispatched run, and how long to keep polling.
3352
3688
  *
3353
3689
  * @public
3354
3690
  */
@@ -3359,13 +3695,15 @@ interface PollOptions {
3359
3695
  readonly timeout?: Duration.Duration | undefined;
3360
3696
  }
3361
3697
  /**
3362
- * Triggering workflows.
3698
+ * Dispatch workflows, wait for the run they start, and list the repository's
3699
+ * workflows.
3363
3700
  *
3364
3701
  * @public
3365
3702
  */
3366
3703
  interface WorkflowDispatchShape {
3367
3704
  /** Fire a `workflow_dispatch` event. GitHub answers 204 with no run id. */
3368
3705
  readonly dispatch: (workflow: string, ref: string, inputs?: Record<string, string>) => Effect.Effect<void, GitHubError, Repo>;
3706
+ /** Read one workflow run's status. */
3369
3707
  readonly runStatus: (runId: number) => Effect.Effect<WorkflowRunStatus, GitHubError, Repo>;
3370
3708
  /**
3371
3709
  * Every workflow defined in the repository.
@@ -3386,10 +3724,11 @@ interface WorkflowDispatchShape {
3386
3724
  * Dispatch, find the run it created, and wait for it to finish.
3387
3725
  *
3388
3726
  * @remarks
3389
- * The wait is `Effect.repeat` with a predicate over the **success** value.
3390
- * The version this replaces encoded "not finished yet" as a sentinel *error*
3391
- * baked into a user-visible error union — control flow in the error channel,
3392
- * which every consumer then had to know not to treat as a failure.
3727
+ * The wait is `Effect.repeat` with a predicate over the **success** value, so
3728
+ * "not finished yet" is never an error. If the run is not found finished
3729
+ * within `poll.timeout`, it fails with a `rejected` `GitHubError` (status
3730
+ * 408). The run is matched by branch, creation time and workflow path, so
3731
+ * concurrent dispatches of the same workflow on the same ref can be confused.
3393
3732
  */
3394
3733
  readonly dispatchAndWait: (workflow: string, ref: string, options?: {
3395
3734
  readonly inputs?: Record<string, string> | undefined;
@@ -3398,11 +3737,33 @@ interface WorkflowDispatchShape {
3398
3737
  }
3399
3738
  declare const WorkflowDispatch_base: Context.ServiceClass<WorkflowDispatch, "@effected/github/WorkflowDispatch", WorkflowDispatchShape>;
3400
3739
  /**
3401
- * Workflow dispatch.
3740
+ * Dispatch workflows, wait for the run they start, and list the repository's
3741
+ * workflows.
3742
+ *
3743
+ * @remarks
3744
+ * Provide it with {@link WorkflowDispatch.layer}, which needs a `GitHubClient`;
3745
+ * each method also needs a `Repo` in `R`. `list` is an `Effect` value, not a
3746
+ * function.
3747
+ *
3748
+ * @example
3749
+ * ```ts
3750
+ * import { WorkflowDispatch } from "@effected/github";
3751
+ * import { Duration, Effect } from "effect";
3752
+ *
3753
+ * const release = Effect.gen(function* () {
3754
+ * const workflows = yield* WorkflowDispatch;
3755
+ * const run = yield* workflows.dispatchAndWait("release.yml", "main", {
3756
+ * inputs: { dryRun: "false" },
3757
+ * poll: { interval: Duration.seconds(15), timeout: Duration.minutes(20) },
3758
+ * });
3759
+ * return run.conclusion;
3760
+ * });
3761
+ * ```
3402
3762
  *
3403
3763
  * @public
3404
3764
  */
3405
3765
  export declare class WorkflowDispatch extends WorkflowDispatch_base {
3766
+ /** The live service, built over a `GitHubClient`. */
3406
3767
  static readonly layer: Layer.Layer<WorkflowDispatch, never, GitHubClient>;
3407
3768
  /** An in-memory double; unstubbed members die naming themselves. */
3408
3769
  static readonly makeTest: (overrides?: Partial<WorkflowDispatchShape>) => WorkflowDispatchShape;