@sentry/junior-github 0.104.1 → 0.105.0

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
@@ -98,8 +98,8 @@ Use `additionalUserScopes` only when a human-identity integration flow requires
98
98
  ## 3) Runtime behavior
99
99
 
100
100
  - When either GitHub skill is active, authenticated `gh` and `git` commands cause the runtime to inject GitHub credentials automatically for the current turn.
101
- - The plugin classifies GitHub traffic from the forwarded HTTP request. Reads use `installation-read`, while `GET /user` uses `user-read`. Allowlisted App-owned mutations and Git smart-HTTP pushes share the repository-scoped `installation-write` grant. User-attachment uploads to `uploads.github.com/user-attachments/assets` use `user-write`. Unknown REST writes and GraphQL mutations are denied.
102
- - `user-read` and the remaining explicitly human `user-write` operations require the actor, or an explicitly delegated user subject, to authorize the GitHub App through the private OAuth flow. Junior-owned issue, pull request, and branch operations do not fall back to user OAuth.
101
+ - The plugin classifies GitHub traffic from the forwarded HTTP request. Reads use `installation-read`, while `GET /user` uses `user-read`. Allowlisted App-owned mutations, Git smart-HTTP pushes, and user-attachment uploads to `uploads.github.com/user-attachments/assets` use repository-scoped `installation-write`. Unknown REST writes and GraphQL mutations are denied.
102
+ - `user-read` and explicitly human `user-write` operations require the actor, or an explicitly delegated user subject, to authorize the GitHub App through the private OAuth flow. Junior-owned issue, pull request, branch, and asset-upload operations do not fall back to user OAuth.
103
103
  - Headless resource-event turns use the `resource-event` system actor and may receive the same repository-scoped installation grants. This lets Junior respond to subscribed pull request events by committing and pushing fixes without inheriting a subscriber's OAuth credential.
104
104
  - Git commits use Junior as author and committer. Resolvable human run actors are credited once with `Co-Authored-By` trailers.
105
105
  - Issued credentials are reused only within the current turn, credential leases are cached by plugin grant and repository lease scope, and upstream 403 permission denials clear the cached lease before the next retry.
package/dist/index.js CHANGED
@@ -857,7 +857,7 @@ var USER_WRITE_REQUIREMENTS = [
857
857
  "requesting GitHub user permission to perform this operation"
858
858
  ];
859
859
  var GITHUB_CREDENTIAL_DOMAINS = ["api.github.com", "github.com"];
860
- var GITHUB_USER_CREDENTIAL_DOMAINS = [
860
+ var GITHUB_ASSET_UPLOAD_CREDENTIAL_DOMAINS = [
861
861
  ...GITHUB_CREDENTIAL_DOMAINS,
862
862
  "uploads.github.com"
863
863
  ];
@@ -1318,7 +1318,7 @@ function createCredentialLease(input) {
1318
1318
  ...input.account ? { account: input.account } : {},
1319
1319
  ...input.authorization ? { authorization: input.authorization } : {},
1320
1320
  expiresAt: new Date(input.expiresAtMs).toISOString(),
1321
- headerTransforms: (input.authorization ? GITHUB_USER_CREDENTIAL_DOMAINS : GITHUB_CREDENTIAL_DOMAINS).map((domain) => ({
1321
+ headerTransforms: (input.domains ?? (input.authorization ? GITHUB_ASSET_UPLOAD_CREDENTIAL_DOMAINS : GITHUB_CREDENTIAL_DOMAINS)).map((domain) => ({
1322
1322
  domain,
1323
1323
  headers: {
1324
1324
  Authorization: authorizationFor(domain, input.token)
@@ -1405,6 +1405,28 @@ function githubRepositoryFromLeaseScope(leaseScope) {
1405
1405
  }
1406
1406
  return { owner: match[1], name: match[2] };
1407
1407
  }
1408
+ function githubRepositoryIdFromUploadUrl(upstreamUrl) {
1409
+ const repositoryId = Number(upstreamUrl.searchParams.get("repository_id"));
1410
+ if (!Number.isSafeInteger(repositoryId) || repositoryId <= 0) {
1411
+ throw new EgressPolicyDenied(
1412
+ "GitHub asset upload request is missing a valid repository_id."
1413
+ );
1414
+ }
1415
+ return repositoryId;
1416
+ }
1417
+ function githubRepositoryIdLeaseScope(repositoryId) {
1418
+ return `repository-id:${repositoryId}`;
1419
+ }
1420
+ function githubRepositoryIdFromLeaseScope(leaseScope) {
1421
+ const match = /^repository-id:(\d+)$/.exec(leaseScope ?? "");
1422
+ const repositoryId = Number(match?.[1]);
1423
+ if (!Number.isSafeInteger(repositoryId) || repositoryId <= 0) {
1424
+ throw new GitHubPluginSetupError(
1425
+ "GitHub asset upload grant is missing a repository id lease scope."
1426
+ );
1427
+ }
1428
+ return repositoryId;
1429
+ }
1408
1430
  async function resolveUserAccount(tokens) {
1409
1431
  const account = await githubRequest("https://api.github.com", "/user", {
1410
1432
  token: tokens.accessToken
@@ -1582,7 +1604,7 @@ async function issueInstallationCredential(options) {
1582
1604
  throw new GitHubPluginSetupError(`Invalid ${options.installationIdEnv}`);
1583
1605
  }
1584
1606
  const appJwt = createAppJwt(appId, options.privateKeyEnv);
1585
- const body = "repositories" in options ? { repositories: options.repositories } : {
1607
+ const body = "repositories" in options ? { repositories: options.repositories } : "repositoryIds" in options ? { repository_ids: options.repositoryIds } : {
1586
1608
  permissions: "permissions" in options ? options.permissions : await options.loadPermissions({ appJwt, installationId })
1587
1609
  };
1588
1610
  const accessTokenResponse = await githubRequest(
@@ -1600,6 +1622,7 @@ async function issueInstallationCredential(options) {
1600
1622
  Date.now() + MAX_LEASE_MS
1601
1623
  );
1602
1624
  return createCredentialLease({
1625
+ ...options.domains ? { domains: options.domains } : {},
1603
1626
  token: parsedToken.token,
1604
1627
  expiresAtMs
1605
1628
  });
@@ -1918,7 +1941,13 @@ async function githubGrantForEgress(ctx) {
1918
1941
  upstreamUrl
1919
1942
  });
1920
1943
  if (isGitHubAssetUploadRequest(method, upstreamUrl)) {
1921
- return grantForAccess("write", "github.asset-upload", "user-write");
1944
+ const repositoryId = githubRepositoryIdFromUploadUrl(upstreamUrl);
1945
+ return grantForAccess(
1946
+ "write",
1947
+ "github.asset-upload",
1948
+ "installation-write",
1949
+ githubRepositoryIdLeaseScope(repositoryId)
1950
+ );
1922
1951
  }
1923
1952
  const smartHttpAccess = githubSmartHttpAccess(upstreamUrl);
1924
1953
  if (smartHttpAccess) {
@@ -2109,6 +2138,18 @@ function githubPlugin(options = {}) {
2109
2138
  });
2110
2139
  }
2111
2140
  if (ctx.grant.name === "installation-write") {
2141
+ if (ctx.grant.reason === "github.asset-upload") {
2142
+ const repositoryId = githubRepositoryIdFromLeaseScope(
2143
+ ctx.grant.leaseScope
2144
+ );
2145
+ return await issueInstallationCredential({
2146
+ appIdEnv,
2147
+ domains: GITHUB_ASSET_UPLOAD_CREDENTIAL_DOMAINS,
2148
+ privateKeyEnv,
2149
+ installationIdEnv,
2150
+ repositoryIds: [repositoryId]
2151
+ });
2152
+ }
2112
2153
  const repository = githubRepositoryFromLeaseScope(
2113
2154
  ctx.grant.leaseScope
2114
2155
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/junior-github",
3
- "version": "0.104.1",
3
+ "version": "0.105.0",
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.104.1"
28
+ "@sentry/junior-plugin-api": "0.105.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^25.9.1",
@@ -13,7 +13,7 @@
13
13
 
14
14
  - **Adopted:** preserve the upstream one-file-per-upload behavior, supported formats, markdown output, and upload endpoint.
15
15
  - **Adopted:** preserve the upstream MIT license in the skill directory as explicitly required.
16
- - **Replaced:** direct `gh auth token` access with Junior's host-managed user credential injection so credentials never enter script output or files.
16
+ - **Replaced:** direct `gh auth token` access with Junior's host-managed, repository-scoped installation credential injection so credentials never enter script output or files.
17
17
  - **Replaced:** numeric repository-id override with explicit `owner/repo`; the script resolves the id through authenticated `gh api`.
18
18
  - **Narrowed:** automatic activation requires a concrete local path and GitHub destination.
19
19
  - **Deferred:** live upload verification because it would create an external GitHub asset; deterministic mocked validation is sufficient for implementation checks.
@@ -23,7 +23,7 @@ Out of scope:
23
23
  - Run `scripts/upload.sh` once per local file.
24
24
  - Return image markdown or a bare video URL.
25
25
  - Surface per-file failures exactly enough for the user to act.
26
- - Use the GitHub plugin's host-managed credential injection; do not retrieve tokens in the script.
26
+ - Use the GitHub plugin's repository-scoped installation credential injection; do not retrieve tokens in the script.
27
27
 
28
28
  ## Reference Architecture
29
29
 
@@ -40,7 +40,7 @@ Out of scope:
40
40
  ## Known Limitations
41
41
 
42
42
  - GitHub's user-attachment endpoint is not part of the documented public REST API.
43
- - A real upload requires GitHub to accept the active user credential for the target repository.
43
+ - A real upload requires GitHub to accept the repository-scoped installation credential for the target repository.
44
44
 
45
45
  ## Maintenance Notes
46
46
 
@@ -1,180 +1,87 @@
1
1
  ---
2
2
  name: github-code
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.
3
+ description: Work with GitHub repositories, source code, branches, commits, pull requests, reviews, diffs, CI, and repository credentials. Use for implementation, source investigation, clone/fetch/branch workflows, PR creation or updates, review feedback, GitHub Actions checks, and repository permission failures. Prefer this skill for repository tasks even when they concern a Sentry product.
4
4
  ---
5
5
 
6
6
  # GitHub Code Operations
7
7
 
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.
8
+ Use `git` and `gh` for repository work. Use `github_createPullRequest`, not `gh pr create`, for new PRs.
16
9
 
17
10
  ## References
18
11
 
19
- | Need | Load |
20
- | ----------------------------------- | -------------------------------------------------------------------------------------- |
21
- | Command syntax, permissions, config | [references/api-surface.md](references/api-surface.md) |
22
- | Failed commands, permission errors | [references/troubleshooting-workarounds.md](references/troubleshooting-workarounds.md) |
12
+ | Open when you need | Read |
13
+ | -------------------------------------- | -------------------------------------------------------------------------------------- |
14
+ | Command syntax, permissions, config | [references/api-surface.md](references/api-surface.md) |
15
+ | Failed commands or permission recovery | [references/troubleshooting-workarounds.md](references/troubleshooting-workarounds.md) |
23
16
 
24
- ## Core rules
17
+ ## Non-negotiable rules
25
18
 
26
- - Resolve the target repo: explicit request wins, then `github.repo` config. Run `jr-rpc config get github.repo` standalone — never chain with `cd`, pipes, `gh`, or `git`.
27
- - Keep `--repo owner/repo` explicit on all `gh` commands; use `git -C PATH` for local repos.
28
- - Do not treat this skill's files or `/skills/...` as target repository source.
29
- - Read repo-local instructions (`AGENTS.md`, `.github/AGENTS.md`, nested equivalents) before editing. When repo, task-specific, and skill instructions conflict, follow the narrower rule.
30
- - Do not overwrite or revert unrelated user changes.
31
- - Do not guess architecture, upstream intent, or feedback validity without reading the relevant code, comments, or failing output.
32
- - Do not claim checks ran unless they did. Do not declare a fix complete without running the chosen check or stating why no credible check was available.
33
- - Stop on: missing repo access, ambiguous target, destructive op without confirmation, or unresolved permission failure.
19
+ - Resolve the repo from the explicit request, then `github.repo`. Run `jr-rpc config get github.repo` standalone.
20
+ - Keep `--repo owner/repo` explicit on `gh`; use `git -C PATH` for local repos.
21
+ - Read applicable `AGENTS.md` files before editing. Narrower repo/task instructions win.
22
+ - Preserve unrelated work. Never force-push, delete refs, or perform destructive merges.
23
+ - Base conclusions on repository evidence. Do not claim a check ran unless it did.
24
+ - Supported App-owned writes use an automatically injected repository-scoped credential. Try the operation before requesting remediation; ask for no user token.
25
+ - Stop for ambiguous targets, missing access, destructive operations, or unresolved upstream permission failures.
34
26
 
35
27
  ## Workflow
36
28
 
37
- ### 1. Resolve target and state
38
-
39
- Identify `owner/repo`, local checkout path, default branch, and current branch.
40
-
41
- For edit operations, also check:
42
-
43
- - current branch and uncommitted changes
44
- - package manager, build tool, monorepo structure
45
- - relevant test/lint/typecheck commands
46
- - repo-local instructions that override this skill
47
-
48
- Choose a validation path before editing:
49
-
50
- - changed-file or package-scoped checks before broad suites
51
- - targeted tests before full runs
52
- - repo-native scripts, fixtures, playgrounds, or smoke checks before one-off scaffolding
53
-
54
- For risky, user-visible, or long-running changes, capture a baseline before editing. If the baseline already fails, record it as pre-existing.
55
-
56
- Prefer existing local checkouts over cloning. Default to shallow clones.
57
-
58
- ### 2. Investigate before editing
59
-
60
- Before changing code, establish:
61
-
62
- - where the behavior lives
63
- - what the current vs. requested behavior is
64
- - root cause or gap the change addresses
65
- - what smallest check can prove the result
66
-
67
- Rules:
68
-
69
- - Prefer narrow evidence: file reads, grep, tests, existing issues/PRs, command output.
70
- - Read referenced issues, PRs, specs, policies, designs, or incidents when the task points to them.
71
- - For product copy, docs, design, or UI work, inspect the real product/project context before inventing wording or layout.
72
- - Before editing a bug, know the failure shape: what breaks, where, and under what condition.
73
- - After a failed fix attempt or strong correction, stop patching symptoms — re-read the evidence and restate the root cause before editing again.
74
- - If the task is investigation-only, answer from evidence without editing.
75
-
76
- **Advisor planning checkpoint:** For a non-trivial implementation — especially architecture or API changes, security-sensitive behavior, concurrency, migrations, broad cross-file edits, or work following failed attempts — call the advisor after gathering enough evidence and before editing. Provide the requirements, relevant code and output, constraints, proposed plan, alternatives considered, risks, and intended validation path. Resolve or explicitly account for material concerns before implementing.
77
-
78
- ### 3. Edit safely
79
-
80
- - Smallest coherent change that satisfies the request.
81
- - Follow repo-local style, patterns, and API boundaries.
82
- - Keep interfaces, exports, config, and public surfaces no broader than the requirement needs.
83
- - When the change touches related call sites or representations, remove duplication or split logic introduced by the change before finalizing.
84
- - No drive-by refactors or speculative cleanup.
85
- - Do not optimize only for passing tests; solve the requested behavior.
86
- - After meaningful edits, run the smallest relevant repo-real check.
87
- - On check failure, inspect root cause before patching again.
88
-
89
- For multi-step or risky work, keep a compact checklist of intent, touched files, verification state, next step, and blockers.
90
-
91
- ### 4. Verify before packaging
92
-
93
- Before committing and creating a PR for code, config, or docs-as-code changes:
94
-
95
- - Run the chosen validation path. Separate pre-existing failures from regressions.
96
- - For docs or instruction-only changes, do a content consistency review instead of claiming automated validation.
97
- - If no credible check exists, say so explicitly.
98
-
99
- **Advisor review checkpoint:** For a non-trivial implementation, call the advisor after inspecting the final diff and running the initial validation path, but before committing, opening or updating a PR, or reporting completion. Provide the diff, relevant surrounding code, requirements, validation results, known limitations, and any remaining risks. Ask specifically for correctness issues, regressions, missed cases, and testing gaps. Investigate material findings, revise as needed, and rerun affected checks before packaging.
100
-
101
- ### 5. Commit
102
-
103
- Default format when the repo does not specify otherwise:
104
-
105
- ```
106
- <type>(<scope>): <Subject>
107
- ```
108
-
109
- Types: `feat`, `fix`, `ref`, `docs`, `test`, `build`, `ci`, `chore`. Imperative present tense, no trailing period, no agent/tool branding. Keep lines under 100 characters.
110
-
111
- Body only when it helps reviewers understand _why_.
112
-
113
- Footer order: `Fixes`/`Refs` lines.
114
-
115
- ### 6. Create or update PR
116
-
117
- Before creating:
118
-
119
- 1. Changes committed on a non-default branch.
120
- 2. Push the branch explicitly: `git push -u origin BRANCH`.
121
- 3. Resolve the actual default branch: `gh repo view owner/repo --json defaultBranchRef --jq .defaultBranchRef.name`.
122
- 4. Create with explicit targeting, using that default branch as `base`: `github_createPullRequest({ repo: "owner/repo", head: "BRANCH", base: "<DEFAULT_BRANCH>", title: "...", body: "...", draft: true })`.
29
+ ### 1. Resolve and inspect
123
30
 
124
- Defaults:
31
+ Identify the repo, checkout, default/current branches, worktree state, repo instructions, package manager, and relevant checks. Prefer an existing checkout; otherwise clone shallowly.
125
32
 
126
- - Draft PRs unless the user or repo says otherwise.
127
- - Reuse an existing PR for the branch; only open a new one when explicitly asked or the work is materially distinct.
128
- - After new commits, re-evaluate title and body against the current diff.
33
+ A shallow clone is for fast inspection, not history rewriting. Before rebasing, merge-base analysis, blame/history work, or comparing against a base absent locally, fetch the needed refs and deepen incrementally. Use `--unshallow` only when bounded deepening is insufficient. Never use a force push to compensate for incomplete history.
129
34
 
130
- **Title:** `<type>(<scope>): <Subject>` same rules as commits, no agent branding.
35
+ For edits, choose the smallest credible validation path before changing files. Capture a baseline when a failure may be pre-existing.
131
36
 
132
- **Body:**
37
+ ### 2. Investigate
133
38
 
134
- - Reviewer-facing prose, not diff narration.
135
- - What changed and why; what was verified; what remains unverified or risky.
136
- - Issue references when relevant.
137
- - No checkbox boilerplate, no PII or customer data in public repos.
39
+ Establish where the behavior lives, current versus requested behavior, root cause or gap, and the smallest proof of correctness. Read linked issues, PRs, specs, and failing output when provided. If the request is investigation-only, report evidence without editing.
138
40
 
139
- **Footers** (in order):
41
+ For non-trivial architecture, API, security, concurrency, migration, or broad cross-file work, use the available advisor after gathering evidence and before editing. Resolve material concerns in the plan.
140
42
 
141
- 1. Issue references (`Fixes #N`, `Refs SENTRY-N`), if any.
43
+ ### 3. Edit
142
44
 
143
- **Assignment:** resolve GitHub handles from evidence (`gh api search/users`, org membership, repo history) before assigning requested reviewers or assignees. Skip assignment when the handle cannot be confirmed.
45
+ Make the smallest coherent change. Follow local patterns and avoid speculative cleanup. After a failed attempt, re-check the root cause before patching again.
144
46
 
145
- ### 7. Subscribe to PR lifecycle
47
+ Before running repo checks, ensure project dependencies are available:
146
48
 
147
- After `github_createPullRequest` succeeds, check whether the result includes a subscribable resource hint. If it does, call `subscribeToResourceEvents` immediately before reporting.
49
+ 1. Detect the package manager and lockfile from repo evidence.
50
+ 2. If dependencies are missing or the check reports missing packages, run the repo-native frozen/immutable install (`pnpm install --frozen-lockfile`, `npm ci`, `yarn install --immutable`, `bun install --frozen-lockfile`, or the documented equivalent).
51
+ 3. Do not regenerate or modify a lockfile merely to make verification run. If the locked install fails, report the exact failure unless dependency changes are part of the task.
148
52
 
149
- - Use the suggested events from the hint; when absent, request review and CI events.
150
- - Write a **self-contained intent** that captures repo, PR number, branch, and a single goal: resolve any review concerns and keep the build green. When an event fires, read the signal, address it, push, and report.
151
- - **Only post an update when there is something meaningful to say.** Report when feedback has been addressed, a build failure has been fixed, the PR is fully green and ready to merge, or the PR has been merged. Stay silent on intermediate CI passes, queued checks, and informational events with no action taken.
53
+ Do not install or repair the GitHub plugin runtime itself; that is manifest-owned setup.
152
54
 
153
- If no subscribable hint is present, skip this step.
55
+ ### 4. Verify and review
154
56
 
155
- ### 8. Report result
57
+ Run targeted changed-file/package checks before broad suites. Separate regressions from baseline failures. For instruction-only changes, run available structural checks and perform a content-consistency review.
156
58
 
157
- Return: repo, branch, PR URL/number (when applicable), checks run with results, pre-existing failures if any, checks not run and why.
59
+ For non-trivial work, review the final diff and initial results with the available advisor before packaging. Address material correctness, regression, and testing concerns, then rerun affected checks.
158
60
 
159
- On failure, report the exact command and error. Do not claim success from partial state.
61
+ ### 5. Package every completed edit
160
62
 
161
- Before finishing, reconcile any plan or checklist stated earlier mark items as done, blocked, or cancelled.
63
+ Unless the user explicitly says not to create a PR, every completed repository edit must end in a pushed branch and PR. Default to draft; honor an explicit user or repo instruction to open it ready for review. Do not stop at local changes or a commit.
162
64
 
163
- ## Operation-specific notes
65
+ 1. Reuse the current non-default branch or create a focused branch.
66
+ 2. Commit using repo conventions; otherwise use `<type>(<scope>): <Subject>` in imperative present tense, with no agent branding.
67
+ 3. Push explicitly with `git push -u origin BRANCH`.
68
+ 4. Resolve the actual default branch.
69
+ 5. Reuse and update an existing PR for the branch; otherwise call `github_createPullRequest` with explicit repo, head, base, title, body, and `draft: true` unless the user or repo explicitly requires ready-for-review.
164
70
 
165
- **Clone** shallow by default; deepen only when history is needed. Read repo instructions after cloning, before editing.
71
+ The PR body should explain what changed and why, checks run, and remaining risks or unverified areas. Never include customer data, PII, secrets, or sensitive thread context, especially in public repositories. Re-evaluate its title/body after material follow-up commits. Resolve requested assignee/reviewer handles from evidence; skip unconfirmed identities.
166
72
 
167
- **Source investigation** use local files first, otherwise clone shallowly or use `gh`. Cite evidence: file paths, symbols, PRs, issues, command output.
73
+ If PR creation is blocked, report the exact failed command/tool call and leave the committed branch intact.
168
74
 
169
- **PR inspection** — read-only `gh pr` and `gh api` commands. Query both conversation comments (`--json comments`) and review comments (`gh api .../pulls/{n}/comments` and `.../reviews`).
75
+ ### 6. Follow and report
170
76
 
171
- **PR mutation** push before create. Use only the allowlisted REST endpoints in the API reference. Merge, close-with-delete, REST ref mutation, and admin operations are unsupported. Git smart HTTP does not independently prevent force updates or ref deletion; rely on GitHub rulesets and do not request destructive pushes.
77
+ When PR creation returns a subscribable resource hint, subscribe to suggested review/CI events. Report only actionable feedback addressed, build failures fixed, fully green/ready state, or merge.
172
78
 
173
- **Workflow dispatch** `gh workflow run` is supported for workflows that declare `workflow_dispatch`. Workflow reruns, cancellations, and other Actions mutations remain unsupported.
79
+ Return: repo, branch, PR URL/number, checks and results, pre-existing failures, and anything not run with the reason.
174
80
 
175
- ## Guardrails
81
+ ## Operation notes
176
82
 
177
- - Default shallow clones; deepen only when needed.
178
- - Do not attempt destructive merges, force pushes, or ref deletion.
179
- - Answer source questions from repo evidence, not product framing or memory.
180
- - Stop and return concrete remediation on missing access or permissions.
83
+ - **Clone/history:** clone shallowly by default; deepen before any operation that relies on omitted ancestry.
84
+ - **PR inspection:** read conversation comments, inline review comments, reviews, diff, and checks.
85
+ - **PR mutation:** push before create; use only supported endpoints in the API reference.
86
+ - **Workflow dispatch:** `gh workflow run` is supported only for workflows declaring `workflow_dispatch`.
87
+ - **Permissions:** a tool-routing denial requires the named tool; only an upstream denial justifies permission remediation.
@@ -0,0 +1,42 @@
1
+ # github-code skill contract
2
+
3
+ ## Intent
4
+
5
+ Guide evidence-first GitHub repository work from inspection through a reviewable result without duplicating command and troubleshooting detail in runtime context.
6
+
7
+ ## Behavioral contract
8
+
9
+ - Resolve and inspect the repository before acting.
10
+ - Preserve unrelated work and reject destructive Git operations.
11
+ - Treat shallow clones as inspection checkouts; fetch/deepen before history-dependent operations and never force-push around missing ancestry.
12
+ - Install repository dependencies with the detected package manager's locked/frozen mode before verification when dependencies are absent.
13
+ - For every completed repository edit, create or update a pushed PR unless the user explicitly opts out; default new PRs to draft while honoring explicit ready-for-review instructions.
14
+ - Report exact validation and permission failures without claiming partial work is complete.
15
+
16
+ ## Runtime architecture
17
+
18
+ - `SKILL.md`: compact workflow and decision rules.
19
+ - `references/api-surface.md`: command and permission lookup.
20
+ - `references/troubleshooting-workarounds.md`: failure recovery.
21
+
22
+ Do not move provider runtime installation, OAuth, or environment setup into this skill; the GitHub plugin manifest owns those concerns.
23
+
24
+ ## Trigger expectations
25
+
26
+ Should trigger for implementation, source inspection, clone/fetch/branch work, commits, PRs, reviews, CI, and repository credential failures.
27
+
28
+ Should not trigger for GitHub issue-only operations, non-GitHub ticketing, product telemetry, or general product documentation with no repository task.
29
+
30
+ ## Validation
31
+
32
+ After material edits:
33
+
34
+ 1. Run the repository skill validator.
35
+ 2. Run formatting or package checks applicable to changed Markdown.
36
+ 3. Confirm all referenced files exist.
37
+ 4. Confirm code-edit completion defaults to a draft PR.
38
+ 5. Confirm dependency installation and shallow-history recovery do not permit lockfile mutation or force-push shortcuts.
39
+
40
+ ## Maintenance
41
+
42
+ Keep workflow policy in `SKILL.md`; move syntax matrices and failure details to the routed references. Remove duplicated rules rather than restating them across sections.
@@ -25,12 +25,14 @@ Treat explicit repo flags as command-targeting safety rails, not as a credential
25
25
  | Operation | Command |
26
26
  | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
27
27
  | Clone repository (default shallow) | `gh repo clone owner/repo [DIRECTORY] -- --depth=1` |
28
- | Deepen shallow clone | `git -C DIRECTORY fetch --depth=N origin` |
29
- | Convert shallow clone to full | `git -C DIRECTORY fetch --unshallow` |
28
+ | Fetch bounded base history | `git -C DIRECTORY fetch --depth=N origin BASE:refs/remotes/origin/BASE` |
29
+ | Deepen base history | `git -C DIRECTORY fetch --deepen=N origin BASE:refs/remotes/origin/BASE` |
30
+ | Convert shallow clone to full | `git -C DIRECTORY fetch --unshallow origin` |
31
+ | Check shallow state | `git -C DIRECTORY rev-parse --is-shallow-repository` |
30
32
  | Check branch | `git -C DIRECTORY branch --show-current` |
31
33
  | Check worktree state | `git -C DIRECTORY status --short --branch` |
32
- | View commit log against base | `git -C DIRECTORY log BASE..HEAD --oneline` |
33
- | Diff against base | `git -C DIRECTORY diff BASE...HEAD` |
34
+ | View commit log against base | `git -C DIRECTORY log origin/BASE..HEAD --oneline` |
35
+ | Diff against base | `git -C DIRECTORY diff origin/BASE...HEAD` |
34
36
  | Resolve default branch | `gh repo view owner/repo --json defaultBranchRef --jq .defaultBranchRef.name` |
35
37
  | Create branch | `git -C DIRECTORY checkout -b BRANCH` |
36
38
  | Stage and commit | `git -C DIRECTORY add -A && git -C DIRECTORY commit -m "message"` |
@@ -66,6 +68,7 @@ jr-rpc config set github.repo owner/repo
66
68
  - Pass extra `git clone` flags after `--` (e.g. `gh repo clone owner/repo -- --depth=1`).
67
69
  - 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
70
  - If the commit changes workflow files under `.github/workflows`, the App installation needs Workflows write in addition to Contents write.
71
+ - Before rebasing, merge-base analysis, blame/history inspection, or a base comparison, check whether the repository is shallow. Fetch a bounded depth of the base into `refs/remotes/origin/BASE`, deepen incrementally until the needed ancestry is present, and compare against `origin/BASE`; use `--unshallow` only when bounded deepening is insufficient. Never force-push to work around missing ancestry.
69
72
  - 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
73
  - Merge, fork creation, workflow reruns or cancellations, REST contents/Git database writes, and repository administration are outside the current write allowlist.
71
74
  - 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.
@@ -2,24 +2,27 @@
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 "..."` 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
- | `unknown flag: --depth` from `gh repo clone` | `git clone` flags were passed before `--`. | Pass clone flags after `--`, for example `gh repo clone owner/repo -- --depth=1`. |
9
- | `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. |
10
- | 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. |
11
- | `GraphQL: Could not resolve to a Repository` | Repo slug is wrong or inaccessible. | Validate `owner/repo` and confirm app installation on target repository. |
12
- | 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. |
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
- | `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
- | 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 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
- | `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` 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. |
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`. |
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. |
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. |
5
+ | Symptom | Likely cause | Fix |
6
+ | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
7
+ | `unknown command "..."` 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
+ | `unknown flag: --depth` from `gh repo clone` | `git clone` flags were passed before `--`. | Pass clone flags after `--`, for example `gh repo clone owner/repo -- --depth=1`. |
9
+ | `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. |
10
+ | 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. |
11
+ | `GraphQL: Could not resolve to a Repository` | Repo slug is wrong or inaccessible. | Validate `owner/repo` and confirm app installation on target repository. |
12
+ | 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. |
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
+ | `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
+ | 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 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
+ | `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` 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. |
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`. |
21
+ | `git blame`, long log history, or old commits are missing after clone | Repo was cloned shallow by design. | Fetch the required ref and deepen it incrementally; use `--unshallow` only when bounded deepening is insufficient. |
22
+ | Rebase, merge-base, or `origin/BASE...HEAD` comparison fails or gives odd ancestry | Required ancestry or the remote-tracking base ref is absent from the shallow clone. | Fetch a bounded depth into `BASE:refs/remotes/origin/BASE`, deepen that base ref until the merge base exists, and compare or rebase against `origin/BASE`. Never force-push around incomplete history. |
23
+ | Tests fail because dependencies or executables are missing | Repository dependencies were not installed. | Detect the lockfile and run the repo-native frozen/immutable install. Do not rewrite the lockfile unless dependency changes are part of the task. |
24
+ | Frozen/immutable dependency install fails | Lockfile drift, unavailable registry, incompatible runtime, or environment issue. | Report the exact install failure. Do not fall back to a lockfile-updating install unless the requested work intentionally changes dependencies. |
25
+ | `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. |
23
26
 
24
27
  ## Retry guidance
25
28