@osdlc/typed-gh 0.9.0 → 0.9.2

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/dist/parse.js CHANGED
@@ -1,21 +1,22 @@
1
1
  /**
2
- * `gh --json` payloads → the typed model.
2
+ * Parsers from `gh --json` payloads to the typed model.
3
3
  *
4
- * Everything here is pure, so an async fan-out can reuse it without going
5
- * near a subprocess, and so the awkward cases can be tested as data.
4
+ * Nothing here has side effects, so code that runs its own calls can reuse
5
+ * it without starting a process, and the hard cases can be tested as data.
6
6
  *
7
- * Two shape hazards this file exists to absorb:
7
+ * It handles two payload differences:
8
8
  *
9
- * 1. **Author logins differ by transport.** GraphQL (`gh pr view --json`)
10
- * returns a suffix-less login (`github-actions`); REST (`gh api`) returns
11
- * the suffixed one (`github-actions[bot]`). Comparing one against the
12
- * other silently never matches, which is how bot noise gets treated as
13
- * human review feedback. Logins are normalized to the suffix-less form
14
- * here, once.
15
- * 2. **`statusCheckRollup` holds two different node types.** A modern
16
- * `CheckRun` carries `name`/`status`/`conclusion`; a legacy
17
- * `StatusContext` carries `context`/`state`. They are folded onto one
18
- * verdict axis so a caller never has to know which it got.
9
+ * 1. Author logins differ between GraphQL and REST. GraphQL
10
+ * (`gh pr view --json`) returns a login without a suffix
11
+ * (`github-actions`). REST (`gh api`) returns the suffixed one
12
+ * (`github-actions[bot]`). Comparing one with the other never matches,
13
+ * and no error shows it. Then a bot's comments are treated as human
14
+ * review feedback. Logins are normalized here, once, to the form without
15
+ * the suffix.
16
+ * 2. `statusCheckRollup` holds two node types. A modern `CheckRun` carries
17
+ * `name`/`status`/`conclusion`. A legacy `StatusContext` carries
18
+ * `context`/`state`. Both map to one verdict, so a caller never has to
19
+ * know which it got.
19
20
  */
20
21
  // ── primitives ──────────────────────────────────────────────────────────────
21
22
  function isRecord(x) {
@@ -31,8 +32,8 @@ function bool(x) {
31
32
  return x === true;
32
33
  }
33
34
  /**
34
- * A comment/review id: GraphQL sends a string node id, REST a numeric one —
35
- * stringify either. A numeric id of 2^53 or more has already lost precision
35
+ * A comment/review id. GraphQL sends a string node id, REST a numeric one.
36
+ * Either becomes a string. A numeric id of 2^53 or more has already lost precision
36
37
  * in `JSON.parse` by the time it gets here.
37
38
  */
38
39
  function idOrNull(x) {
@@ -47,15 +48,14 @@ function list(x) {
47
48
  }
48
49
  // ── actors ──────────────────────────────────────────────────────────────────
49
50
  /**
50
- * Strip a single trailing `[bot]` suffix — REST shape folded to GraphQL shape.
51
- *
52
- * The one normalization that makes a login from either transport comparable.
51
+ * Strip a single trailing `[bot]` suffix, so a REST login matches the
52
+ * GraphQL one.
53
53
  */
54
54
  export function normalizeAuthorLogin(login) {
55
55
  return login.endsWith('[bot]') ? login.slice(0, -'[bot]'.length) : login;
56
56
  }
57
57
  /**
58
- * Parse an author node from either transport (`author` or REST's `user`).
58
+ * Parse an author node from GraphQL (`author`) or REST (`user`).
59
59
  * Null when there is no login, or the login is empty once `[bot]` is removed.
60
60
  */
61
61
  export function parseActor(x) {
@@ -67,7 +67,7 @@ export function parseActor(x) {
67
67
  return null;
68
68
  return {
69
69
  login,
70
- // `is_bot` is REST/GraphQL-dependent; the suffix is the portable signal.
70
+ // Only some payloads carry `is_bot`. The suffix works for both.
71
71
  isBot: bool(x['is_bot']) || raw.endsWith('[bot]'),
72
72
  };
73
73
  }
@@ -75,10 +75,9 @@ export function parseActor(x) {
75
75
  /**
76
76
  * Conclusions that mean the check failed.
77
77
  *
78
- * `ACTION_REQUIRED` is deliberately not here: it means a human must do
79
- * something, not that the build broke, and the existing consumers treat it as
80
- * neutral. Widening this set changes triage verdicts, so it is a decision to
81
- * make on purpose rather than by adding a plausible-looking member.
78
+ * `ACTION_REQUIRED` is not here on purpose. It means a person must do
79
+ * something, not that the build broke, and callers treat it as neutral.
80
+ * Adding a member changes every caller's verdicts, so decide it on purpose.
82
81
  */
83
82
  const FAILED_CONCLUSIONS = new Set(['FAILURE', 'TIMED_OUT', 'CANCELLED', 'STARTUP_FAILURE']);
84
83
  /** Legacy StatusContext `state` values that mean failure. */
@@ -104,12 +103,11 @@ export function parseCheckRun(x) {
104
103
  return null;
105
104
  const status = str(x['status']).toUpperCase();
106
105
  const conclusion = strOrNull(x['conclusion']);
107
- // `detailsUrl` is the modern CheckRun field; `targetUrl` is the legacy
108
- // StatusContext one — a raw payload occasionally carries either under a
109
- // `name`-shaped node, so read both rather than assume the field follows
110
- // the node-type split strictly.
106
+ // `detailsUrl` is the modern CheckRun field and `targetUrl` the legacy
107
+ // StatusContext one. A payload sometimes carries either on a node with a
108
+ // `name`, so read both.
111
109
  const url = strOrNull(x['detailsUrl']) ?? strOrNull(x['targetUrl']);
112
- // Still running: not a pass. Reading "no failure yet" as green merges red.
110
+ // Still running, so not a pass. If "no failure yet" counted as green, a red build could merge.
113
111
  if (status !== '' && status !== 'COMPLETED') {
114
112
  return { name, status, conclusion, verdict: 'pending', url };
115
113
  }
@@ -127,7 +125,7 @@ export function anyCheckFailed(checks) {
127
125
  return checks.some((c) => c.verdict === 'failure');
128
126
  }
129
127
  // ── the pull request ────────────────────────────────────────────────────────
130
- /** Parse a `labels` field (PR, issue, or a bare `gh label list` array) into {@link Label} rows — the one label-array parse every `gh` caller shares. Skips an item with no name, or an empty-string name (indistinguishable from absent). */
128
+ /** Parse a `labels` field (PR, issue, or a bare `gh label list` array) into {@link Label} rows. Every label list in this package goes through it. Skips an item with no name, or an empty name, which reads the same as no name. */
131
129
  export function parseLabels(x) {
132
130
  const out = [];
133
131
  for (const item of list(x)) {
@@ -170,12 +168,12 @@ function parseReviews(x) {
170
168
  }
171
169
  return out;
172
170
  }
173
- /** `mergeable` is tri-state; anything unrecognized (or absent) is UNKNOWN. */
171
+ /** `mergeable` has three states. Anything unknown, or absent, is UNKNOWN. */
174
172
  function parseMergeable(x) {
175
173
  const v = str(x).toUpperCase();
176
174
  return v === 'MERGEABLE' || v === 'CONFLICTING' ? v : 'UNKNOWN';
177
175
  }
178
- /** gh returns `""` for "no decision yet"; the model says `null`. */
176
+ /** gh returns `""` for "no decision yet". The model says `null`. */
179
177
  function parseReviewDecision(x) {
180
178
  const v = strOrNull(x);
181
179
  return v === 'APPROVED' || v === 'CHANGES_REQUESTED' || v === 'REVIEW_REQUIRED' ? v : null;
@@ -183,8 +181,8 @@ function parseReviewDecision(x) {
183
181
  /**
184
182
  * One PR from a `gh --json` object, or null when it carries no usable number.
185
183
  *
186
- * Total by construction: a field `gh` was not asked for lands at its "not
187
- * known" value rather than `undefined`, so the result is safe to build from
184
+ * Every field gets a value. A field `gh` was not asked for gets its "not
185
+ * known" value, not `undefined`, so the result is safe to build from
188
186
  * any field subset.
189
187
  */
190
188
  export function parsePullRequest(raw) {
@@ -257,7 +255,7 @@ export function parsePrSearchHit(raw) {
257
255
  return {
258
256
  number,
259
257
  title: str(raw['title']),
260
- // Search answers in lower case; `PullRequest.state` is upper case.
258
+ // Search answers in lower case. `PullRequest.state` is upper case.
261
259
  state: str(raw['state']).toUpperCase(),
262
260
  url: str(raw['url']),
263
261
  isDraft: bool(raw['isDraft']),
package/dist/repo.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Turning a git remote into a GitHub coordinate.
2
+ * Reading the GitHub owner and repository from a git remote, and a pull
3
+ * request from a URL or what a person typed.
3
4
  *
4
- * This is `@osdlc/typed-git`'s `parseGitUrl` applied to the one question a
5
- * GitHub client always ends up asking. It lives here rather than in each
6
- * caller because the hand-rolled version is always a regex over
7
- * `remote.origin.url`, and that regex is always missing a URL shape —
8
- * scp-style, a trailing `.git`, an `ssh://` port, a bare `owner/repo`.
5
+ * `parseOwnerRepo` uses `@osdlc/typed-git`'s `parseGitUrl`. It lives here so
6
+ * callers do not each write a regex over `remote.origin.url`. Such a regex
7
+ * usually misses a URL form: scp-style, a trailing `.git`, an `ssh://` port,
8
+ * or a bare `owner/repo`.
9
9
  */
10
10
  import type { OwnerRepo } from './types.ts';
11
11
  /**
@@ -27,11 +27,11 @@ export interface PullRequestRef extends OwnerRepo {
27
27
  *
28
28
  * Accepts `https://<host>/<owner>/<repo>/pull/<n>` with or without a scheme,
29
29
  * a trailing slash, a sub-page (`/files`, `/commits`), a query string or a
30
- * fragment — every shape a browser's address bar hands over. The host is
30
+ * fragment, as copied from a browser's address bar. The host is
31
31
  * `github.com` (a `www.` prefix is dropped) or a GitHub Enterprise host such
32
- * as `github.acme.com` or `acme.ghe.com`; without a scheme the host must
33
- * contain a dot. `parseGitUrl` is the wrong tool here: it reads `/pull/<n>`
34
- * as part of the project path.
32
+ * as `github.acme.com` or `acme.ghe.com`. Without a scheme the host must
33
+ * contain a dot. `parseGitUrl` does not fit here, because it reads
34
+ * `/pull/<n>` as part of the project path.
35
35
  */
36
36
  export declare function parsePrUrl(url: string): PullRequestRef | null;
37
37
  /**
@@ -58,9 +58,9 @@ export type PrRef = {
58
58
  * Read what a person typed to name a pull request: a number, `#42`,
59
59
  * `owner/name#42`, a URL, or a branch name. Null when it is none of these.
60
60
  *
61
- * Pure: it starts no process. Digits are read as a number first, the way
62
- * `gh pr view 42` reads them; `orBranch` keeps the branch reading. The
63
- * clients' `prFind` tries both.
61
+ * It starts no process. Digits are read as a number first, the way
62
+ * `gh pr view 42` reads them. `orBranch` keeps the text for reading it as a
63
+ * branch. The clients' `prFind` tries both.
64
64
  */
65
65
  export declare function parsePrRef(input: string): PrRef | null;
66
66
  /** True for `owner/name` as GitHub spells it. */
package/dist/repo.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Turning a git remote into a GitHub coordinate.
2
+ * Reading the GitHub owner and repository from a git remote, and a pull
3
+ * request from a URL or what a person typed.
3
4
  *
4
- * This is `@osdlc/typed-git`'s `parseGitUrl` applied to the one question a
5
- * GitHub client always ends up asking. It lives here rather than in each
6
- * caller because the hand-rolled version is always a regex over
7
- * `remote.origin.url`, and that regex is always missing a URL shape —
8
- * scp-style, a trailing `.git`, an `ssh://` port, a bare `owner/repo`.
5
+ * `parseOwnerRepo` uses `@osdlc/typed-git`'s `parseGitUrl`. It lives here so
6
+ * callers do not each write a regex over `remote.origin.url`. Such a regex
7
+ * usually misses a URL form: scp-style, a trailing `.git`, an `ssh://` port,
8
+ * or a bare `owner/repo`.
9
9
  */
10
10
  import { parseGitUrl } from '@osdlc/typed-git';
11
11
  /**
@@ -31,11 +31,11 @@ export function ownerRepoSlug(r) {
31
31
  *
32
32
  * Accepts `https://<host>/<owner>/<repo>/pull/<n>` with or without a scheme,
33
33
  * a trailing slash, a sub-page (`/files`, `/commits`), a query string or a
34
- * fragment — every shape a browser's address bar hands over. The host is
34
+ * fragment, as copied from a browser's address bar. The host is
35
35
  * `github.com` (a `www.` prefix is dropped) or a GitHub Enterprise host such
36
- * as `github.acme.com` or `acme.ghe.com`; without a scheme the host must
37
- * contain a dot. `parseGitUrl` is the wrong tool here: it reads `/pull/<n>`
38
- * as part of the project path.
36
+ * as `github.acme.com` or `acme.ghe.com`. Without a scheme the host must
37
+ * contain a dot. `parseGitUrl` does not fit here, because it reads
38
+ * `/pull/<n>` as part of the project path.
39
39
  */
40
40
  export function parsePrUrl(url) {
41
41
  const m = /^(?:(https?:)\/\/)?([a-z0-9](?:[a-z0-9.-]*[a-z0-9])?(?::\d+)?)\/([^/\s]+)\/([^/\s]+)\/pull\/(\d+)(?:[/?#].*)?$/i.exec(url.trim());
@@ -58,9 +58,9 @@ export function parsePrUrl(url) {
58
58
  * Read what a person typed to name a pull request: a number, `#42`,
59
59
  * `owner/name#42`, a URL, or a branch name. Null when it is none of these.
60
60
  *
61
- * Pure: it starts no process. Digits are read as a number first, the way
62
- * `gh pr view 42` reads them; `orBranch` keeps the branch reading. The
63
- * clients' `prFind` tries both.
61
+ * It starts no process. Digits are read as a number first, the way
62
+ * `gh pr view 42` reads them. `orBranch` keeps the text for reading it as a
63
+ * branch. The clients' `prFind` tries both.
64
64
  */
65
65
  export function parsePrRef(input) {
66
66
  const text = input.trim();
package/dist/run.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  /**
2
- * `runVerb` and `runVerbAsync` — run one {@link GhVerb} through a runner the
2
+ * `runVerb` and `runVerbAsync` run one {@link GhVerb} through a runner the
3
3
  * caller owns, with everything the verb asks for applied.
4
4
  *
5
5
  * A verb carries more than `argv`: `input` (a payload on stdin), `env` (the
6
6
  * target host as `GH_HOST`), and `checked` (whether a non-zero exit throws).
7
- * `verb.parse(await runner.run(verb.argv))` drops the first two without a
8
- * word, so a query goes to github.com and a review is never sent. These two
9
- * apply all of it, as `Gh` and `AsyncGh` do; both clients call them.
7
+ * `verb.parse(await runner.run(verb.argv))` drops the first two with no
8
+ * error, so a query goes to github.com and a review is never sent. These two
9
+ * functions apply all of it. `Gh` and `AsyncGh` call them too.
10
10
  */
11
11
  import type { AsyncCommandRunner, CommandRunner } from '@osdlc/command-seam';
12
12
  import type { GhVerb } from './verbs.ts';
@@ -18,20 +18,19 @@ export interface RunVerbOptions {
18
18
  }
19
19
  /** {@link RunVerbOptions} for {@link runVerbAsync}, with the abort signal. */
20
20
  export interface RunVerbAsyncOptions extends RunVerbOptions {
21
- /** Aborts the call; the runner stops the child. */
21
+ /** Aborts the call. The runner stops the child process. */
22
22
  signal?: AbortSignal | undefined;
23
23
  }
24
24
  /**
25
- * Run `verb` through `runner` and return its parsed value, honouring the
26
- * verb's `input`, `env`, `timeoutMs` and `checked`, and its checked or
27
- * unchecked contract: a failed `gh` throws a `FailureError` carrying the
28
- * classified `GhFailure`, output that cannot be read throws one of kind
29
- * `unreadable`, and a query for one thing answers `null` when GitHub says
30
- * there is no such thing.
25
+ * Run `verb` through `runner` and return its parsed value. It applies the
26
+ * verb's `input`, `env` and `checked`, and the `timeoutMs` option. A failed
27
+ * `gh` throws a `FailureError` carrying the classified `GhFailure`. Output
28
+ * that cannot be read throws one of kind `unreadable`. A query for one thing
29
+ * returns `null` when GitHub says there is no such thing.
31
30
  *
32
- * A plain `(binary, argv, opts) => result` function is not a runner: wrap it
31
+ * A plain `(binary, argv, opts) => result` function is not a runner. Wrap it
33
32
  * as `{ run: (argv, opts) => fn('gh', argv, opts) }`.
34
33
  */
35
34
  export declare function runVerb<T>(verb: GhVerb<T>, runner: CommandRunner, opts: RunVerbOptions): T;
36
- /** {@link runVerb} for an `AsyncCommandRunner`; rejects where that throws. */
35
+ /** {@link runVerb} for an `AsyncCommandRunner`. It rejects where `runVerb` throws. */
37
36
  export declare function runVerbAsync<T>(verb: GhVerb<T>, runner: AsyncCommandRunner, opts: RunVerbAsyncOptions): Promise<T>;
package/dist/run.js CHANGED
@@ -1,23 +1,22 @@
1
1
  /**
2
- * `runVerb` and `runVerbAsync` — run one {@link GhVerb} through a runner the
2
+ * `runVerb` and `runVerbAsync` run one {@link GhVerb} through a runner the
3
3
  * caller owns, with everything the verb asks for applied.
4
4
  *
5
5
  * A verb carries more than `argv`: `input` (a payload on stdin), `env` (the
6
6
  * target host as `GH_HOST`), and `checked` (whether a non-zero exit throws).
7
- * `verb.parse(await runner.run(verb.argv))` drops the first two without a
8
- * word, so a query goes to github.com and a review is never sent. These two
9
- * apply all of it, as `Gh` and `AsyncGh` do; both clients call them.
7
+ * `verb.parse(await runner.run(verb.argv))` drops the first two with no
8
+ * error, so a query goes to github.com and a review is never sent. These two
9
+ * functions apply all of it. `Gh` and `AsyncGh` call them too.
10
10
  */
11
11
  import { runCheckedGh, runCheckedGhAsync, settle } from "./doors.js";
12
12
  /**
13
- * Run `verb` through `runner` and return its parsed value, honouring the
14
- * verb's `input`, `env`, `timeoutMs` and `checked`, and its checked or
15
- * unchecked contract: a failed `gh` throws a `FailureError` carrying the
16
- * classified `GhFailure`, output that cannot be read throws one of kind
17
- * `unreadable`, and a query for one thing answers `null` when GitHub says
18
- * there is no such thing.
13
+ * Run `verb` through `runner` and return its parsed value. It applies the
14
+ * verb's `input`, `env` and `checked`, and the `timeoutMs` option. A failed
15
+ * `gh` throws a `FailureError` carrying the classified `GhFailure`. Output
16
+ * that cannot be read throws one of kind `unreadable`. A query for one thing
17
+ * returns `null` when GitHub says there is no such thing.
19
18
  *
20
- * A plain `(binary, argv, opts) => result` function is not a runner: wrap it
19
+ * A plain `(binary, argv, opts) => result` function is not a runner. Wrap it
21
20
  * as `{ run: (argv, opts) => fn('gh', argv, opts) }`.
22
21
  */
23
22
  export function runVerb(verb, runner, opts) {
@@ -31,7 +30,7 @@ export function runVerb(verb, runner, opts) {
31
30
  const result = verb.checked ? runCheckedGh(runner, verb.argv, run) : runner.run(verb.argv, run);
32
31
  return settle(verb, result, runner.binary);
33
32
  }
34
- /** {@link runVerb} for an `AsyncCommandRunner`; rejects where that throws. */
33
+ /** {@link runVerb} for an `AsyncCommandRunner`. It rejects where `runVerb` throws. */
35
34
  export async function runVerbAsync(verb, runner, opts) {
36
35
  const run = { cwd: opts.cwd };
37
36
  if (verb.input !== undefined)
package/dist/sync.d.ts CHANGED
@@ -1,18 +1,19 @@
1
1
  /**
2
- * `Gh` — the synchronous GitHub client, the companion of `@osdlc/typed-git`'s
2
+ * `Gh`: the synchronous GitHub client, the companion of `@osdlc/typed-git`'s
3
3
  * `Git`, bound to one working directory and one {@link CommandRunner}.
4
4
  *
5
- * Authentication is `gh`'s, not ours: no token is read, stored, or passed.
6
- * That is the whole reason this shells out to the CLI instead of speaking
7
- * REST — the credential already exists in the user's keychain, and a library
8
- * that reaches for `GITHUB_TOKEN` is a library that can leak one.
5
+ * `gh` handles authentication. No token is read, stored, or passed. That is
6
+ * why this runs the CLI instead of calling the REST API. The credential is
7
+ * already in the user's keychain. A library that reads `GITHUB_TOKEN` can
8
+ * leak it.
9
9
  *
10
- * The same three doors as the git client. The plain method returns a value
11
- * or throws: a failed `gh` throws a `FailureError` carrying the classified
12
- * `GhFailure`, output that cannot be read throws one of kind `unreadable`, and a query for one thing (`prView`, `issueView`,
13
- * `repoView`) answers `null` when GitHub says there is no such thing.
14
- * `gh.try.*` returns the failure as a `Result<T, GhFailure>`; `gh.soft.*` returns
15
- * `null` for it. `raw`/`rawChecked` are the escape hatches.
10
+ * It has the same three call styles as the git client. The plain method
11
+ * returns a value or throws. A failed `gh` throws a `FailureError` carrying
12
+ * the classified `GhFailure`. Output that cannot be read throws one of kind
13
+ * `unreadable`. A query for one thing (`prView`, `issueView`, `repoView`)
14
+ * returns `null` when GitHub says there is no such thing. `gh.try.*` returns
15
+ * the failure as a `Result<T, GhFailure>`. `gh.soft.*` returns `null` for it.
16
+ * `raw` and `rawChecked` run any `gh` call.
16
17
  */
17
18
  import { type CommandResult, type CommandRunner } from '@osdlc/command-seam';
18
19
  import { type Soft, type TriedSync } from './doors.ts';
@@ -20,12 +21,12 @@ import * as v from './verbs.ts';
20
21
  import type { ApiOptions, ApiResponse, AuthStatus, GhTarget, IssueListOptions, ListResult, PrListOptions } from './verbs.ts';
21
22
  import type { IssueRow, Label, OwnerRepo, PrSearchHit, PullRequest, Repository } from './types.ts';
22
23
  /**
23
- * Factory of per-binary runners — the injectable subprocess seam a CLI tail
24
- * threads through its call graph. Production uses `spawnRunner`; tests supply
25
- * a recording factory so a whole tail runs offline.
24
+ * Makes a runner for a binary. A CLI passes one factory to every place that
25
+ * runs a command. Real code uses `spawnRunner`. Tests pass a factory that
26
+ * records calls, so the CLI runs offline.
26
27
  */
27
28
  export type RunnerFactory = (binary: string) => CommandRunner;
28
- /** Default factory: real, spawnSync-backed runners. */
29
+ /** The default factory: real runners that use `spawnSync`. */
29
30
  export declare const defaultRunnerFactory: RunnerFactory;
30
31
  /** What a client is built with: the runner, and the repository and host it talks to. */
31
32
  export interface GhOptions extends GhTarget {
@@ -60,50 +61,52 @@ export declare class Gh {
60
61
  withRepo(repo: string): Gh;
61
62
  /**
62
63
  * The whole surface again, returning a `Result<T, GhFailure>` instead of
63
- * throwing: `gh.try.prList()` is `{ ok: true, value } | { ok: false, error }`.
64
+ * throwing. `gh.try.prList()` is `{ ok: true, value } | { ok: false, error }`.
64
65
  * A query for one thing that finds nothing is `ok: true` with `null`. See
65
66
  * `./doors.ts`.
66
67
  *
67
- * The type leaves out the escape hatches and the pure helpers; at runtime
68
- * the proxy wraps `raw` and `rawChecked` too. Call those on the client itself.
68
+ * The type leaves out `raw`, `rawChecked` and the helpers that run nothing.
69
+ * At runtime the proxy wraps `raw` and `rawChecked` too. Call those on the
70
+ * client itself.
69
71
  */
70
72
  get try(): TriedSync<Gh>;
71
73
  /**
72
74
  * Each query again, returning `null` instead of throwing when `gh` fails. A
73
- * mutation has no soft form. Do not gate a write on a `null` from `soft`:
74
- * it is the answer for "could not ask" as well as for "nothing there". Use
75
+ * mutation has no soft form. Do not decide a write on a `null` from `soft`.
76
+ * It is the answer for "could not ask" as well as for "nothing there". Use
75
77
  * `try` where the difference matters.
76
78
  */
77
79
  get soft(): Soft<Gh>;
78
- /** Unchecked passthrough for verbs not yet lifted into the API. */
80
+ /** Run any `gh` call and return the result, whatever the exit code. */
79
81
  raw(argv: string[], opts?: {
80
82
  timeoutMs?: number | undefined;
81
83
  }): CommandResult;
82
- /** Checked passthrough — throws the classified failure on a non-zero exit. */
84
+ /** Run any `gh` call. Throws the classified failure on a non-zero exit. */
83
85
  rawChecked(argv: string[], opts?: {
84
86
  timeoutMs?: number | undefined;
85
87
  }): CommandResult;
86
- /** Run one verb from the table, honouring its checked/unchecked contract. */
88
+ /** Run one verb from the table, checked or unchecked as the verb says. */
87
89
  private exec;
88
- /** {@link exec} for a verb that never answers `null` as a value: a failed or unreadable run throws. */
90
+ /** {@link exec} for a verb that never returns `null` as a value. A failed or unreadable run throws. */
89
91
  private read;
90
- /** Pull requests matching `opts`. Throws when gh fails; `soft.prList` gives null instead. */
92
+ /** Pull requests matching `opts`. Throws when gh fails. `soft.prList` gives null instead. */
91
93
  prList(opts?: PrListOptions & {
92
94
  timeoutMs?: number | undefined;
93
95
  }): ListResult<PullRequest>;
94
96
  /**
95
- * One PR by number, branch or URL, with the heavy fields; null when there is
96
- * no such PR. Throws when gh fails otherwise.
97
+ * One PR by number, branch or URL, with the full field set. Null when there
98
+ * is no such PR. Throws when gh fails otherwise.
97
99
  */
98
100
  prView(ref: number | string, opts?: {
99
101
  fields?: readonly string[] | undefined;
100
102
  timeoutMs?: number | undefined;
101
103
  }): PullRequest | null;
102
104
  /**
103
- * The one PR that `input` names, or null: what a person typed, such as `42`,
104
- * `#42`, `owner/name#42`, a URL or a branch (read by `parsePrRef`).
105
+ * The one PR that `input` names, or null. `input` is what a person typed,
106
+ * such as `42`, `#42`, `owner/name#42`, a URL or a branch (read by
107
+ * `parsePrRef`).
105
108
  *
106
- * Digits are a PR number first; when no such PR comes back, they are tried
109
+ * Digits are a PR number first. When no such PR comes back, they are tried
107
110
  * as a branch. A branch gives its open PR, or else its newest closed or
108
111
  * merged one, so a tool run after the merge still finds it. Fields default
109
112
  * to {@link PR_LIST_FIELDS}.
@@ -115,28 +118,26 @@ export declare class Gh {
115
118
  /**
116
119
  * The open PR whose head exactly equals `branch`, or null.
117
120
  *
118
- * Defaults to {@link PR_REF_FIELDS}: identifying a PR must not cost a
119
- * merge-state computation. Pass `opts.fields` to ask for more (e.g.
120
- * `isDraft`) in the SAME call, when a caller needs a field beyond identity
121
- * before deciding whether to act on the PR at all — asking `prList`/`prView`
122
- * separately would cost a second round trip for the common case where the
123
- * caller already knows it wants that field up front.
121
+ * Defaults to {@link PR_REF_FIELDS}, so finding a PR does not make GitHub
122
+ * compute the merge state. Pass `opts.fields` to ask for more (such as
123
+ * `isDraft`) in the same call. That saves a second `prList` or `prView`
124
+ * call when the caller already knows it needs the field.
124
125
  */
125
126
  openPrFor(branch: string, opts?: {
126
127
  limit?: number | undefined;
127
128
  fields?: readonly string[] | undefined;
128
129
  }): PullRequest | null;
129
130
  /**
130
- * {@link prView}, re-asked until GitHub settles the merge state.
131
+ * {@link prView}, asked again until GitHub has computed the merge state.
131
132
  *
132
- * GitHub computes mergeability lazily: the first query kicks it off and
133
- * answers `UNKNOWN` while it runs. A caller that believes that first answer
134
- * mis-triages every PR that is merely slow to compute, so this re-asks
135
- * `attempts` times before returning what it has. The last answer is
136
- * returned whether or not it settled — `UNKNOWN` is a legitimate final
137
- * verdict and callers must still handle it.
133
+ * GitHub computes mergeability only when asked. The first query starts it
134
+ * and answers `UNKNOWN` while it runs. A caller that trusts that first
135
+ * answer misjudges every PR whose computation is slow. So this asks up to
136
+ * `attempts` times while the answer is `UNKNOWN`. The last answer is
137
+ * returned either way. `UNKNOWN` can be the final answer, and callers must
138
+ * still handle it.
138
139
  *
139
- * `sleep` is injected so a test does not spend real seconds waiting.
140
+ * `sleep` is an option so a test does not spend real seconds waiting.
140
141
  */
141
142
  prViewSettled(number: number, opts?: {
142
143
  attempts?: number | undefined;
@@ -149,15 +150,15 @@ export declare class Gh {
149
150
  timeoutMs?: number | undefined;
150
151
  }): string;
151
152
  /**
152
- * A REST GET through `gh api`. Never throws for a failed call, in any door:
153
- * failure is `ok: false` on the returned {@link ApiResponse}.
153
+ * A REST GET through `gh api`. Never throws for a failed call, in any call
154
+ * style. Failure is `ok: false` on the returned {@link ApiResponse}.
154
155
  */
155
156
  api(endpoint: string, opts?: ApiOptions & {
156
157
  timeoutMs?: number | undefined;
157
158
  }): ApiResponse;
158
159
  /**
159
- * A GraphQL query; each page's `data`. Throws on a failed or partial result;
160
- * `soft.graphql` gives null. See the `graphql` verb.
160
+ * A GraphQL query. Returns each page's `data`. Throws on a failed or partial
161
+ * result. `soft.graphql` gives null. See the `graphql` verb.
161
162
  *
162
163
  * @experimental
163
164
  */
@@ -173,7 +174,7 @@ export declare class Gh {
173
174
  issueList(opts?: IssueListOptions & {
174
175
  timeoutMs?: number | undefined;
175
176
  }): ListResult<IssueRow>;
176
- /** One issue with its labels; null when there is no such issue. Throws when gh fails otherwise. */
177
+ /** One issue with its labels, or null when there is no such issue. Throws when gh fails otherwise. */
177
178
  issueView(number: number, opts?: {
178
179
  timeoutMs?: number | undefined;
179
180
  }): IssueRow | null;
@@ -193,25 +194,26 @@ export declare class Gh {
193
194
  /** True iff the `gh` binary is on PATH and runs. */
194
195
  installed(): boolean;
195
196
  /**
196
- * True iff `gh` holds credentials. Asked on its own only by a caller that
197
- * reports the two halves separately — "gh is missing" and "gh is not logged
198
- * in" are different things to tell a person, and a report that collapses
199
- * them sends someone to install software they already have.
197
+ * True iff `gh` holds credentials. Call it on its own to report the two
198
+ * checks separately. "gh is missing" and "gh is not logged in" need
199
+ * different fixes. A report that merges them sends someone to install
200
+ * software they already have.
200
201
  */
201
202
  authenticated(): boolean;
202
- /** Login state and what `gh auth status` printed; `authenticated()` is its `ok`. */
203
+ /** Login state and what `gh auth status` printed. `authenticated()` is its `ok`. */
203
204
  authStatus(): AuthStatus;
204
205
  /**
205
- * True iff `gh` is installed AND authenticated — the two-step probe.
206
+ * True iff `gh` is installed and authenticated.
206
207
  *
207
- * Short-circuits: an absent binary cannot be asked about credentials.
208
+ * Skips the auth check when `gh` is not installed, since there is nothing to
209
+ * ask.
208
210
  */
209
211
  ready(): boolean;
210
212
  /**
211
213
  * `{owner, repo}` parsed from the remote URL you pass, or null when it is
212
214
  * null or names no project.
213
215
  *
214
- * Pure: it reads no git config, starts no process and does not ask GitHub.
216
+ * It reads no git config, starts no process and does not ask GitHub.
215
217
  */
216
218
  ownerRepo(remoteUrl: string | null): OwnerRepo | null;
217
219
  /** Open a PR and return its URL ('' if gh printed none). */
@@ -221,12 +223,12 @@ export declare class Gh {
221
223
  title?: string | undefined;
222
224
  body?: string | undefined;
223
225
  }): void;
224
- /** The PR's unified diff; throws the classified failure when gh cannot produce it. */
226
+ /** The PR's unified diff. Throws the classified failure when gh cannot produce it. */
225
227
  prDiff(number: number): string;
226
- /** Post one conversation comment on a PR; returns its URL ('' if gh printed none). */
228
+ /** Post one conversation comment on a PR. Returns its URL ('' if gh printed none). */
227
229
  prComment(number: number, body: string): string;
228
230
  /**
229
- * Create a `COMMENT` review with inline comments; returns the review's URL ('' if none came back).
231
+ * Create a `COMMENT` review with inline comments. Returns the review's URL ('' if none came back).
230
232
  *
231
233
  * @experimental
232
234
  */
@@ -238,12 +240,12 @@ export declare class Gh {
238
240
  /** Mark a PR ready for review (`draft: false`) or convert it to a draft (`draft: true`). */
239
241
  prSetDraft(number: number, draft: boolean): void;
240
242
  /**
241
- * Rewrite one PR conversation comment's body. `commentId` is the numeric REST id; anything else throws `RangeError`.
243
+ * Rewrite one PR conversation comment's body. `commentId` is the numeric REST id. Anything else throws `RangeError`.
242
244
  *
243
245
  * @experimental
244
246
  */
245
247
  issueCommentEdit(commentId: string, body: string): void;
246
- /** Merge a PR; GitHub refuses when its head is no longer `opts.headSha`. */
248
+ /** Merge a PR. GitHub refuses when its head is no longer `opts.headSha`. */
247
249
  prMerge(number: number, opts: {
248
250
  method: v.PrMergeMethod;
249
251
  headSha: string;
@@ -259,8 +261,8 @@ export declare class Gh {
259
261
  }): void;
260
262
  /**
261
263
  * Swap an issue's label: remove `currentLabel` (when given) and add
262
- * `newLabel`, in a single `gh issue edit` call — never a briefly-unlabeled
263
- * or briefly-double-labeled intermediate state.
264
+ * `newLabel`, in a single `gh issue edit` call. The issue is never left
265
+ * with neither label or both labels in between.
264
266
  */
265
267
  setIssueLabel(number: number, currentLabel: string | null, newLabel: string): void;
266
268
  }