@sentry/junior-github 0.102.1 → 0.102.3

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/SETUP.md CHANGED
@@ -64,7 +64,7 @@ vercel env update GITHUB_APP_PRIVATE_KEY production --sensitive < ./github-app-p
64
64
 
65
65
  Repeat for `preview` and `development` as needed. After env changes, redeploy so the new deployment picks up updated values.
66
66
 
67
- ### Optional permission overrides
67
+ ### Optional permission declaration
68
68
 
69
69
  By default, `installation-read` grants read the app installation's current permission envelope once per process and scopes read-capable permissions down to `read` when requesting a token. To declare the GitHub App permission envelope in the plugin and avoid that installation lookup, pass `appPermissions` when registering the plugin:
70
70
 
@@ -81,11 +81,11 @@ githubPlugin({
81
81
  });
82
82
  ```
83
83
 
84
- Junior records these permissions as plugin capabilities. The configured values are the maximum GitHub App envelope Junior may need for writes. Installation-read token requests remain read-only by requesting read-capable configured permissions at `read` level and omitting GitHub permission fields that have no `read` value. GitHub remains the source of truth for whether a permission name or level exists.
84
+ Junior records these permissions as plugin capabilities. Installation-read token requests remain read-only by requesting read-capable configured permissions at `read` level and omitting GitHub permission fields that have no `read` value. Installation-write token requests intentionally omit the `permissions` field, so GitHub applies the complete permission envelope approved on the App installation. GitHub remains the source of truth for whether a permission name or level exists.
85
85
 
86
86
  GitHub App user-to-server tokens do not use OAuth scopes as their permission model. Their effective access is limited by the GitHub App's installed permissions, the app installation's repository access, and the requesting user's own GitHub access. Repository-scoped installation tokens instead use the App permission envelope and installation repository access without borrowing the requesting user's authority. GitHub returns an empty `scope` value for user-to-server tokens, so Junior cannot verify granted scopes from the token response.
87
87
 
88
- If you pass `additionalUserScopes`, Junior includes those values in the authorization URL and records the requested scope string as a local reauthorization contract. This does not expand or prove GitHub API permissions configure GitHub App permissions with `appPermissions` and in the GitHub App settings for provider-enforced access:
88
+ If you pass `additionalUserScopes`, Junior includes those values in the authorization URL and records the requested scope string as a local reauthorization contract. This does not expand or prove GitHub API permissions. Configure provider-enforced access in the GitHub App settings; `appPermissions` only declares capabilities and controls read-token downscoping:
89
89
 
90
90
  ```ts
91
91
  githubPlugin({
@@ -93,7 +93,7 @@ githubPlugin({
93
93
  });
94
94
  ```
95
95
 
96
- Use `additionalUserScopes` only when a human-identity integration flow requires specific GitHub OAuth scope parameters in the authorization URL. Do not rely on it to authorize Junior-owned repository or workflow writes — those use repository-scoped installation tokens and the configured GitHub App permissions.
96
+ Use `additionalUserScopes` only when a human-identity integration flow requires specific GitHub OAuth scope parameters in the authorization URL. Do not rely on it to authorize Junior-owned repository or workflow writes — those use repository-scoped installation tokens and the permissions approved on the GitHub App installation.
97
97
 
98
98
  ## 3) Runtime behavior
99
99
 
@@ -128,12 +128,12 @@ new resources through the typed tools, for example
128
128
  Use `gh` for the allowlisted lifecycle operations described by the skill.
129
129
 
130
130
  `gh` supports either direct `GITHUB_TOKEN` (for local debugging) or sandbox-level header injection.
131
- The plugin uses installation credentials for read-only GitHub traffic, workflow dispatches, allowlisted issue and pull request mutations, and Git smart-HTTP pushes. GitHub App permissions still need to cover the operation: actions for workflow dispatches, issues for issue edits/comments/labels, contents for pushes, pull requests for PR mutations, and workflows for workflow-file pushes.
131
+ The plugin uses installation credentials for read-only GitHub traffic, workflow dispatches, allowlisted issue and pull request mutations, and Git smart-HTTP pushes. The installed GitHub App permissions still need to cover the operation: actions for workflow dispatches, issues for issue edits/comments/labels, contents for pushes, pull requests for PR mutations, and workflows for workflow-file pushes.
132
132
 
133
133
  Committing and pushing code uses more than one GitHub surface:
134
134
 
135
135
  - Creating the local Git commit does not call GitHub. Junior sets the GitHub App bot as author and committer and credits resolvable human actors with `Co-Authored-By` trailers.
136
- - Pushing a branch with Git smart HTTP (`git push`) uses the repository-scoped `installation-write` grant and requires `Contents: write`. If `Workflows: write` is configured, it is included so workflow-file changes can be pushed.
136
+ - Pushing a branch with Git smart HTTP (`git push`) uses the repository-scoped `installation-write` grant and requires the App installation to have `Contents: write`. Workflow-file changes also require the installation to have `Workflows: write`.
137
137
  - The smart-HTTP classifier does not distinguish Junior-managed branches or independently detect force updates or ref deletion. Use GitHub branch protection and limit the App installation to repositories where Junior may push.
138
138
  - REST Git database and ref writes are denied by the current write allowlist. Use Git smart HTTP (`git push`) for branch updates instead.
139
139
  - Opening the PR after the branch exists is separate: `github_createPullRequest` needs pull-request write permission, but it should not create or push commits itself.
@@ -144,10 +144,10 @@ Repository scoping and the egress allowlist are the write boundaries. Credential
144
144
 
145
145
  Be careful with mixed-surface PR commands. Use the allowlisted REST endpoints
146
146
  rather than GraphQL-backed `gh pr` mutation commands. PR-native title, body,
147
- base, state, ready-for-review, and requested-reviewer changes use the pull
148
- request grant. Comments, labels, and assignees use GitHub's issue endpoints and
149
- the issue grant. Merge, branch deletion, REST ref mutation, and administration
150
- remain unsupported API operations.
147
+ base, state, ready-for-review, and requested-reviewer changes use pull request
148
+ endpoints. Comments, labels, and assignees use GitHub's issue endpoints. All
149
+ allowlisted bot writes share `installation-write`; merge, branch deletion, REST
150
+ ref mutation, and administration remain unsupported API operations.
151
151
 
152
152
  For PR creation in automation, push explicitly and pass that branch as `head`:
153
153
 
package/dist/index.d.ts CHANGED
@@ -12,11 +12,12 @@ export interface GitHubPluginOptions {
12
12
  */
13
13
  additionalUserScopes?: string[];
14
14
  /**
15
- * GitHub App installation permissions Junior should request for app tokens.
15
+ * GitHub App permissions Junior should expose as capabilities and downscope
16
+ * to read for installation-read tokens.
16
17
  *
17
18
  * Keys may use GitHub permission names with underscores or hyphens. Junior
18
- * records these as plugin capabilities and requests read-only installation
19
- * tokens by scoping read-capable permissions down to `read`.
19
+ * records these as plugin capabilities. Installation-write tokens inherit
20
+ * the App installation's complete permission envelope.
20
21
  * GitHub remains the source of truth for whether a permission exists.
21
22
  */
22
23
  appPermissions?: GitHubAppPermissions;
package/dist/index.js CHANGED
@@ -848,6 +848,7 @@ var USER_REFRESH_TIMEOUT_MS = 2e4;
848
848
  var GITHUB_GRAPHQL_RESPONSE_BODY_LIMIT_BYTES = 64 * 1024;
849
849
  var HTTP_READ_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
850
850
  var USER_TOKEN_GRANTS = /* @__PURE__ */ new Set(["user-read", "user-write"]);
851
+ var CREATE_TOOL_ROUTING_GUIDANCE = "This is a Junior tool-routing denial, not a GitHub permission failure. Do not ask the user for GitHub permissions; retry with the required Junior tool.";
851
852
  var USER_WRITE_REQUIREMENTS = [
852
853
  "requesting GitHub user permission to perform this operation"
853
854
  ];
@@ -1572,17 +1573,16 @@ async function issueInstallationCredential(options) {
1572
1573
  throw new GitHubPluginSetupError(`Invalid ${options.installationIdEnv}`);
1573
1574
  }
1574
1575
  const appJwt = createAppJwt(appId, options.privateKeyEnv);
1575
- const permissions = options.permissions ?? await options.loadPermissions?.({ appJwt, installationId });
1576
+ const body = "repositories" in options ? { repositories: options.repositories } : {
1577
+ permissions: "permissions" in options ? options.permissions : await options.loadPermissions({ appJwt, installationId })
1578
+ };
1576
1579
  const accessTokenResponse = await githubRequest(
1577
1580
  "https://api.github.com",
1578
1581
  `/app/installations/${installationId}/access_tokens`,
1579
1582
  {
1580
1583
  method: "POST",
1581
1584
  token: appJwt,
1582
- body: {
1583
- ...permissions ? { permissions } : {},
1584
- ...options.repositories ? { repositories: options.repositories } : {}
1585
- }
1585
+ body
1586
1586
  }
1587
1587
  );
1588
1588
  const parsedToken = parseInstallationTokenResponse(accessTokenResponse);
@@ -1865,7 +1865,7 @@ function assertGitHubWriteAllowed(input) {
1865
1865
  input.bodyText
1866
1866
  )) {
1867
1867
  throw new EgressPolicyDenied(
1868
- "GitHub issue creation must use the github_createIssue tool so Junior can own idempotency and the conversation footer."
1868
+ `GitHub issue creation must use the github_createIssue tool so Junior can own idempotency and the conversation footer. ${CREATE_TOOL_ROUTING_GUIDANCE}`
1869
1869
  );
1870
1870
  }
1871
1871
  if (isGitHubPullCreateRestRequest(input.method, input.upstreamUrl) || isGitHubPullCreateGraphqlMutation(
@@ -1874,21 +1874,17 @@ function assertGitHubWriteAllowed(input) {
1874
1874
  input.bodyText
1875
1875
  )) {
1876
1876
  throw new EgressPolicyDenied(
1877
- "GitHub pull request creation must use the github_createPullRequest tool so Junior can own idempotency and the conversation footer."
1877
+ `GitHub pull request creation must use the github_createPullRequest tool so Junior can own idempotency and the conversation footer. ${CREATE_TOOL_ROUTING_GUIDANCE}`
1878
1878
  );
1879
1879
  }
1880
1880
  }
1881
- function grantRequirements(reason) {
1882
- return reason === "github.user-write" ? USER_WRITE_REQUIREMENTS : void 0;
1883
- }
1884
1881
  function grantForAccess(access, reason, name, leaseScope) {
1885
- const requirements = grantRequirements(reason);
1886
1882
  return {
1887
1883
  name,
1888
1884
  access,
1889
1885
  ...leaseScope ? { leaseScope } : {},
1890
1886
  reason,
1891
- ...requirements ? { requirements } : {}
1887
+ ...reason === "github.user-write" ? { requirements: USER_WRITE_REQUIREMENTS } : {}
1892
1888
  };
1893
1889
  }
1894
1890
  function repositoryLeaseScope(upstreamUrl) {
@@ -1971,10 +1967,10 @@ function githubPlugin(options = {}) {
1971
1967
  const appIdEnv = options.appIdEnv ?? GITHUB_APP_ID_ENV;
1972
1968
  const privateKeyEnv = options.privateKeyEnv ?? GITHUB_APP_PRIVATE_KEY_ENV;
1973
1969
  const installationIdEnv = options.installationIdEnv ?? GITHUB_INSTALLATION_ID_ENV;
1974
- const appPermissions = normalizePermissions(options.appPermissions);
1975
- const appReadPermissions = appPermissions ? readGrantPermissions(appPermissions) : void 0;
1970
+ const declaredAppPermissions = normalizePermissions(options.appPermissions);
1971
+ const declaredReadPermissions = declaredAppPermissions ? readGrantPermissions(declaredAppPermissions) : void 0;
1976
1972
  const loadReadPermissions = createPermissionCache();
1977
- const appCapabilities = permissionCapabilities(appPermissions);
1973
+ const appCapabilities = permissionCapabilities(declaredAppPermissions);
1978
1974
  const userScopes = normalizeScopeList(options.additionalUserScopes);
1979
1975
  const userScope = userScopes.length ? userScopes.join(" ") : void 0;
1980
1976
  return defineJuniorPlugin({
@@ -2090,7 +2086,7 @@ function githubPlugin(options = {}) {
2090
2086
  appIdEnv,
2091
2087
  privateKeyEnv,
2092
2088
  installationIdEnv,
2093
- ...appReadPermissions ? { permissions: appReadPermissions } : { loadPermissions: loadReadPermissions }
2089
+ ...declaredReadPermissions ? { permissions: declaredReadPermissions } : { loadPermissions: loadReadPermissions }
2094
2090
  });
2095
2091
  }
2096
2092
  if (ctx.grant.name === "installation-write") {
@@ -2101,12 +2097,8 @@ function githubPlugin(options = {}) {
2101
2097
  appIdEnv,
2102
2098
  privateKeyEnv,
2103
2099
  installationIdEnv,
2104
- ...appPermissions ? {
2105
- permissions: {
2106
- ...appPermissions,
2107
- metadata: "read"
2108
- }
2109
- } : {},
2100
+ // This repository-only variant cannot downscope the installed
2101
+ // App envelope with an operation-specific permission body.
2110
2102
  repositories: [repository.name]
2111
2103
  });
2112
2104
  }
@@ -1,6 +1,6 @@
1
1
  export type GitHubAppPermissionLevel = "admin" | "read" | "write";
2
2
  export type GitHubAppPermissions = Record<string, GitHubAppPermissionLevel>;
3
- /** Validate configured GitHub App permissions before using them in grants. */
3
+ /** Validate the configured GitHub App capability and read-token declaration. */
4
4
  export declare function normalizePermissions(permissions: GitHubAppPermissions | undefined): GitHubAppPermissions | undefined;
5
5
  /** Build the read-only installation-token permission body. */
6
6
  export declare function readGrantPermissions(permissions: Record<string, unknown> | undefined): Record<string, "read">;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-github",
3
- "version": "0.102.1",
3
+ "version": "0.102.3",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "@sinclair/typebox": "^0.34.49",
27
27
  "zod": "^4.4.3",
28
- "@sentry/junior-plugin-api": "0.102.1"
28
+ "@sentry/junior-plugin-api": "0.102.3"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^25.9.1",
@@ -1,11 +1,18 @@
1
1
  ---
2
2
  name: github-code
3
- description: Work with GitHub repositories, source code, branches, commits, pushes, pull requests, reviews, diffs, and CI runs. Use for repo implementation tasks, source-code investigation, cloning/fetching, branch and push workflows, PR creation, PR updates, PR review feedback, and GitHub Actions checks. Prefer this skill for repository and code tasks even when the repo concerns Sentry products.
3
+ description: Work with GitHub repositories, source code, branches, commits, pushes, pull requests, reviews, diffs, CI runs, and GitHub App credentials for branch and PR workflows. Use for repo implementation tasks, source-code investigation, cloning/fetching, branch and push workflows, PR creation or updates, PR review feedback, GitHub credential or permission failures involving repositories, pushes, or PRs, and GitHub Actions checks. Prefer this skill for repository and code tasks even when the repo concerns Sentry products.
4
4
  ---
5
5
 
6
6
  # GitHub Code Operations
7
7
 
8
- Use `gh` and `git` for repository checkout, source investigation, code changes, commits, and pull request inspection or mutation. Use Junior's `github_createPullRequest` tool for new pull requests.
8
+ ## Credential contract
9
+
10
+ - Supported App-owned GitHub operations require no user-managed credential. Junior automatically mints and injects a repository-scoped GitHub App `installation-write` credential.
11
+ - For a pull request from an existing branch, push the branch first, then call `github_createPullRequest`; both operations receive the automatic installation credential.
12
+ - Do not ask the user to authorize GitHub, provide a token, or grant Contents/Pull requests permissions before trying a supported operation.
13
+ - Request remediation only after a supported operation returns evidence of an upstream provider denial. A Junior tool-routing denial means retry with the required tool, not request permissions.
14
+
15
+ Use `gh` and `git` for repository checkout, source investigation, code changes, commits, and pull request inspection or mutation. Use Junior's `github_createPullRequest` tool instead of `gh pr create` for new pull requests.
9
16
 
10
17
  ## References
11
18
 
@@ -65,9 +65,9 @@ jr-rpc config set github.repo owner/repo
65
65
  - Prefer `--json` output for machine-readable parsing where available.
66
66
  - Pass extra `git clone` flags after `--` (e.g. `gh repo clone owner/repo -- --depth=1`).
67
67
  - A local `git commit` does not call GitHub. Pushing that commit uses Junior's repository-scoped installation credential and requires `github.contents.write` on the target repo.
68
- - If the commit changes workflow files under `.github/workflows`, expect `github.workflows.write` in addition to contents write.
68
+ - If the commit changes workflow files under `.github/workflows`, the App installation needs Workflows write in addition to Contents write.
69
69
  - Before `github_createPullRequest`, push the head branch explicitly and resolve the target repo's default branch for `base`. That push requires GitHub write access to the remote.
70
70
  - Merge, fork creation, workflow reruns or cancellations, REST contents/Git database writes, and repository administration are outside the current write allowlist.
71
71
  - If the explicit `git push` fails with 401/403 or another access/permission error, verify the repo context and retry once. If it still fails, load troubleshooting guidance and report the exact command failure.
72
- - PR comments, labels, and assignees use GitHub's issue endpoints and therefore the issue grant; use the `github-issues` REST guidance for those operations.
72
+ - PR comments, labels, and assignees use GitHub's issue endpoints; use the `github-issues` REST guidance for those operations. All allowlisted bot writes share the same repository-scoped `installation-write` credential.
73
73
  - Return actionable errors for access, permission, not-found, and validation failures.
@@ -13,9 +13,10 @@ Use this table to recover quickly while keeping operations deterministic.
13
13
  | `junior-auth-required provider=github grant=user-write` | User-to-server OAuth is missing or stale for a human-identity operation. | Follow the private OAuth prompt; do not ask the user to paste or manage tokens manually. |
14
14
  | `git push` fails with 401/403 or auth/permission output | Write permission is missing, app installation is too narrow, or remote is wrong. | Verify the remote and repo context, retry once, then confirm app permissions and installation scope if it still fails. |
15
15
  | Bash result includes `permission_denied` with `source: "upstream"` | GitHub returned 403 after Junior injected the named grant. | Do not call this a Junior runtime block. Use the message, connected account, upstream target, grant requirements, accepted-permissions, and SSO fields to explain the GitHub denial. |
16
- | 403 Forbidden | App lacks required permission on repo or install scope is too narrow. | Verify the repo context, then confirm GitHub App permissions and installation scope. |
16
+ | 403 without `permission_denied` where `source: "upstream"` | Junior may have rejected an unsupported route before contacting GitHub. | Read the response body. Follow any required-tool instruction; do not ask for GitHub permissions unless the failure is confirmed upstream. |
17
17
  | `gh auth status` shows `Token scopes: none` | Expected for GitHub App user-to-server tokens. | Do not treat this as read-only proof. Use the failed command, `permission_denied.acceptedPermissions`, and GitHub App permissions instead. |
18
- | `github_createPullRequest` fails with auth/permission errors | The branch was not pushed first, or repo context is wrong. | Push the branch explicitly first, then retry `github_createPullRequest` with explicit `repo`, `head`, and `base` values. |
18
+ | `github_createPullRequest` returns upstream 401/403 | The App installation or target repository does not permit the operation. | Use the structured upstream denial to verify installation scope and accepted permissions; do not request user OAuth for this bot-owned operation. |
19
+ | `github_createPullRequest` returns 422 for `head` | The head branch was not pushed or the explicit head ref is wrong. | Push the branch, then retry with explicit `repo`, `head`, and `base` values. |
19
20
  | `github_createPullRequest` fails with 422 validation on `base` | The `base` branch does not exist in the target repo. | Resolve the default branch with `gh repo view owner/repo --json defaultBranchRef --jq .defaultBranchRef.name`, then retry with that value as `base`. |
20
21
  | `git blame`, long log history, or old commits are missing after clone | Repo was cloned shallow by design. | Deepen incrementally with `git -C DIRECTORY fetch --depth=N origin`, or `git -C DIRECTORY fetch --unshallow` when full history is required. |
21
22
  | `sandbox setup failed (dnf install gh failed ...)` | `gh` package not available from the plugin runtime dependency bootstrap. | Report the plugin runtime bootstrap failure; do not try to repair package installation from the skill workflow. |
@@ -2,18 +2,19 @@
2
2
 
3
3
  Use this table to recover quickly while keeping operations deterministic.
4
4
 
5
- | Symptom | Likely cause | Fix |
6
- | ------------------------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
7
- | `unknown command "issue"` from `gh` | CLI version too old or wrong binary in the plugin runtime. | Verify `gh --version`; if it is unavailable or too old, report that the GitHub plugin runtime dependency is not available. |
8
- | `Missing required option --repo` | Repo not passed and no default was resolved. | Resolve with `jr-rpc config get github.repo`; pass `--repo owner/repo` explicitly when missing. |
9
- | Command affects or authenticates against the wrong repo | Stale `github.repo` default or authenticated command missing explicit repo. | Pass `--repo owner/repo` for the target repository, or update `github.repo` before retrying. |
10
- | `GraphQL: Could not resolve to a Repository` | Repo slug is wrong or inaccessible. | Validate `owner/repo` and confirm app installation on target repository. |
11
- | 401 Unauthorized | Issued GitHub credentials were rejected upstream. | Verify the target repo, then use the grant/auth signal to distinguish stale user OAuth from app installation or host env setup. |
12
- | `junior-auth-required provider=github grant=user-write` | User-to-server OAuth is missing or stale for a human-identity operation. | Follow the private OAuth prompt; do not ask the user to paste or manage tokens manually. |
13
- | 403 Forbidden | App lacks required permission on repo or install scope is too narrow. | Verify the repo context, then confirm GitHub App permissions and installation scope. |
14
- | 404 Not Found | Issue number or repo is wrong. | Validate repo + issue ID with `gh issue view NUMBER --repo owner/repo`. |
15
- | Issue label mutation fails | Wrong REST payload or wrong repo context. | Use the allowlisted issue labels endpoint with an explicit `owner/repo` path and valid JSON input. |
16
- | Comment command fails with empty body | JSON input is missing a non-empty `body`. | Ensure the REST comment payload contains a non-empty `body` before retrying. |
5
+ | Symptom | Likely cause | Fix |
6
+ | ---------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
7
+ | `unknown command "issue"` from `gh` | CLI version too old or wrong binary in the plugin runtime. | Verify `gh --version`; if it is unavailable or too old, report that the GitHub plugin runtime dependency is not available. |
8
+ | `Missing required option --repo` | Repo not passed and no default was resolved. | Resolve with `jr-rpc config get github.repo`; pass `--repo owner/repo` explicitly when missing. |
9
+ | Command affects or authenticates against the wrong repo | Stale `github.repo` default or authenticated command missing explicit repo. | Pass `--repo owner/repo` for the target repository, or update `github.repo` before retrying. |
10
+ | `GraphQL: Could not resolve to a Repository` | Repo slug is wrong or inaccessible. | Validate `owner/repo` and confirm app installation on target repository. |
11
+ | 401 Unauthorized | Issued GitHub credentials were rejected upstream. | Verify the target repo, then use the grant/auth signal to distinguish stale user OAuth from app installation or host env setup. |
12
+ | `junior-auth-required provider=github grant=user-write` | User-to-server OAuth is missing or stale for a human-identity operation. | Follow the private OAuth prompt; do not ask the user to paste or manage tokens manually. |
13
+ | 403 without `permission_denied` where `source: "upstream"` | Junior may have rejected an unsupported route before contacting GitHub. | Read the response body. Follow any required-tool instruction; do not ask for GitHub permissions unless the failure is confirmed upstream. |
14
+ | `permission_denied` with `source: "upstream"` | GitHub rejected the injected installation credential. | Verify the target, accepted permissions, and App installation scope; do not request user OAuth for a bot-owned issue operation. |
15
+ | 404 Not Found | Issue number or repo is wrong. | Validate repo + issue ID with `gh issue view NUMBER --repo owner/repo`. |
16
+ | Issue label mutation fails | Wrong REST payload or wrong repo context. | Use the allowlisted issue labels endpoint with an explicit `owner/repo` path and valid JSON input. |
17
+ | Comment command fails with empty body | JSON input is missing a non-empty `body`. | Ensure the REST comment payload contains a non-empty `body` before retrying. |
17
18
 
18
19
  ## Retry guidance
19
20