pr-shepherd 0.34.0 → 0.35.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/.claude-plugin/plugin.json +3 -2
- package/.grok-plugin/marketplace.json +17 -0
- package/README.md +56 -39
- package/bin/api.d.mts +80 -0
- package/bin/api.mjs +236 -0
- package/bin/checks/classify.d.mts +41 -0
- package/bin/checks/startup-failures.d.mts +2 -0
- package/bin/checks/superseded.d.mts +21 -0
- package/bin/checks/triage.d.mts +4 -0
- package/bin/classify/apply.d.mts +18 -0
- package/bin/classify/apply.mjs +4 -0
- package/bin/classify/loader.d.mts +10 -0
- package/bin/classify/types.d.mts +35 -0
- package/bin/cli/args.d.mts +18 -0
- package/bin/cli/clean-formatter.d.mts +2 -0
- package/bin/cli/default-poll.d.mts +2 -0
- package/bin/cli/duration-flag.d.mts +2 -0
- package/bin/cli/duration.d.mts +13 -0
- package/bin/cli/fence.d.mts +1 -0
- package/bin/cli/fix-formatter-extra.d.mts +3 -0
- package/bin/cli/fix-formatter.d.mts +2 -0
- package/bin/cli/fix-formatter.mjs +6 -6
- package/bin/cli/formatters.d.mts +7 -0
- package/bin/cli/handlers.d.mts +4 -0
- package/bin/cli/handlers.mjs +11 -10
- package/bin/cli/help-command-pages.d.mts +231 -0
- package/bin/cli/help-command-pages.mjs +106 -1
- package/bin/cli/help-iterate-poll-pages.d.mts +4 -0
- package/bin/cli/help-iterate-poll-pages.mjs +4 -2
- package/bin/cli/help-log-file-page.d.mts +1 -0
- package/bin/cli/help-top-page.d.mts +1 -0
- package/bin/cli/help-top-page.mjs +14 -15
- package/bin/cli/help.d.mts +236 -0
- package/bin/cli/help.mjs +17 -0
- package/bin/cli/iterate-emitter.d.mts +8 -0
- package/bin/cli/iterate-flags.d.mts +11 -0
- package/bin/cli/iterate-formatter.d.mts +19 -0
- package/bin/cli/iterate-instructions.d.mts +6 -0
- package/bin/cli/iterate-lean.d.mts +12 -0
- package/bin/cli/journal-formatter.d.mts +2 -0
- package/bin/cli/journal-formatter.mjs +15 -0
- package/bin/cli/journal-handler.d.mts +1 -0
- package/bin/cli/journal-handler.mjs +7 -20
- package/bin/cli/list-formatters.d.mts +76 -0
- package/bin/cli/list-formatters.mjs +9 -9
- package/bin/cli/mark-files-as-viewed-flags.d.mts +11 -0
- package/bin/cli/mark-files-as-viewed-formatter.d.mts +2 -0
- package/bin/cli/mutate-formatter.d.mts +2 -0
- package/bin/cli/poll-handler.d.mts +1 -0
- package/bin/cli/poll-handler.mjs +2 -2
- package/bin/cli/resolve-validators.d.mts +3 -0
- package/bin/cli/resolve-validators.mjs +3 -3
- package/bin/cli/runner.d.mts +7 -0
- package/bin/cli/suggestion-renderer.d.mts +3 -0
- package/bin/cli/validate-default-args.d.mts +6 -0
- package/bin/cli-parser.d.mts +2 -0
- package/bin/cli-parser.mjs +72 -16
- package/bin/commands/check-annotations.d.mts +5 -0
- package/bin/commands/check-status.d.mts +3 -0
- package/bin/commands/check-terminal-report.d.mts +5 -0
- package/bin/commands/check.d.mts +6 -0
- package/bin/commands/check.mjs +2 -1
- package/bin/commands/clean.d.mts +21 -0
- package/bin/commands/commit-suggestion-instruction.d.mts +8 -0
- package/bin/commands/commit-suggestion-instruction.mjs +3 -3
- package/bin/commands/commit-suggestion.d.mts +8 -0
- package/bin/commands/commit-suggestion.mjs +11 -10
- package/bin/commands/iterate/check-instructions.d.mts +16 -0
- package/bin/commands/iterate/check-instructions.mjs +3 -3
- package/bin/commands/iterate/classify.d.mts +18 -0
- package/bin/commands/iterate/classify.mjs +4 -4
- package/bin/commands/iterate/escalate.d.mts +31 -0
- package/bin/commands/iterate/escalate.mjs +7 -4
- package/bin/commands/iterate/fix-code.d.mts +25 -0
- package/bin/commands/iterate/helpers.d.mts +13 -0
- package/bin/commands/iterate/helpers.mjs +4 -1
- package/bin/commands/iterate/index.d.mts +2 -0
- package/bin/commands/iterate/index.mjs +5 -2
- package/bin/commands/iterate/render.d.mts +5 -0
- package/bin/commands/iterate/render.mjs +8 -6
- package/bin/commands/iterate/reruns.d.mts +20 -0
- package/bin/commands/iterate/stall.d.mts +6 -0
- package/bin/commands/journal/index.d.mts +14 -0
- package/bin/commands/journal/index.mjs +1 -0
- package/bin/commands/journal/transform.d.mts +22 -0
- package/bin/commands/log-file.d.mts +5 -0
- package/bin/commands/mark-files-as-viewed.d.mts +26 -0
- package/bin/commands/mark-files-as-viewed.mjs +1 -0
- package/bin/commands/poll.d.mts +10 -0
- package/bin/commands/poll.mjs +1 -0
- package/bin/commands/ready-delay.d.mts +29 -0
- package/bin/commands/ready-mergeability.d.mts +15 -0
- package/bin/commands/resolve-mutate.d.mts +4 -0
- package/bin/commands/resolve-mutate.mjs +1 -0
- package/bin/commands/resolve.d.mts +4 -0
- package/bin/commands/shepherd-journal.d.mts +7 -0
- package/bin/commands/shepherd-journal.mjs +2 -2
- package/bin/comments/authors.d.mts +14 -0
- package/bin/comments/marker.d.mts +2 -0
- package/bin/comments/minimize-policy.d.mts +4 -0
- package/bin/comments/pending-ops.d.mts +15 -0
- package/bin/comments/rate-limit.d.mts +18 -0
- package/bin/comments/resolve.d.mts +34 -0
- package/bin/comments/resolve.mjs +1 -0
- package/bin/comments/review-thread-markers.d.mts +8 -0
- package/bin/comments/review-visibility.d.mts +28 -0
- package/bin/comments/sha-poll.d.mts +2 -0
- package/bin/comments/thread-visibility.d.mts +11 -0
- package/bin/comments/visible-comments.d.mts +11 -0
- package/bin/config/load.d.mts +60 -0
- package/bin/config/load.mjs +72 -1
- package/bin/config.json +0 -2
- package/bin/execution-context.d.mts +9 -0
- package/bin/execution-context.mjs +19 -0
- package/bin/exit-codes.d.mts +51 -0
- package/bin/github/activity.d.mts +3 -0
- package/bin/github/activity.mjs +7 -0
- package/bin/github/batch-parser-helpers.d.mts +22 -0
- package/bin/github/batch-parsers.d.mts +3 -0
- package/bin/github/batch-parsers.mjs +6 -0
- package/bin/github/batch-raw-types.d.mts +207 -0
- package/bin/github/batch-response.d.mts +4 -0
- package/bin/github/batch.d.mts +22 -0
- package/bin/github/branch-protection.d.mts +3 -0
- package/bin/github/check-annotations.d.mts +2 -0
- package/bin/github/client.d.mts +46 -0
- package/bin/github/client.mjs +7 -2
- package/bin/github/errors.d.mts +25 -0
- package/bin/github/gql/batch-pr.gql +5 -0
- package/bin/github/gql/review-thread-comments.gql +1 -0
- package/bin/github/graphql-http.d.mts +19 -0
- package/bin/github/graphql-response.d.mts +7 -0
- package/bin/github/http-auth.d.mts +4 -0
- package/bin/github/http-request.d.mts +7 -0
- package/bin/github/http-utils.d.mts +11 -0
- package/bin/github/http.d.mts +5 -0
- package/bin/github/pagination.d.mts +45 -0
- package/bin/github/queries.d.mts +24 -0
- package/bin/github/rest-http.d.mts +2 -0
- package/bin/github/thread-comments.d.mts +2 -0
- package/bin/index.d.mts +10 -0
- package/bin/index.mjs +1 -1
- package/bin/log/log-file.d.mts +28 -0
- package/bin/log/session.d.mts +31 -0
- package/bin/log/setup.d.mts +6 -0
- package/bin/mcp/index.d.mts +5 -0
- package/bin/mcp/index.mjs +8 -0
- package/bin/mcp/server.d.mts +8 -0
- package/bin/mcp/server.mjs +157 -0
- package/bin/mcp-stdio.d.mts +2 -0
- package/bin/mcp-stdio.mjs +7 -0
- package/bin/merge-status/derive.d.mts +19 -0
- package/bin/reporters/agent.d.mts +23 -0
- package/bin/reporters/agent.mjs +3 -0
- package/bin/state/base.d.mts +1 -0
- package/bin/state/bot-cr-seen.d.mts +51 -0
- package/bin/state/bot-cr-seen.mjs +1 -1
- package/bin/state/fix-attempts.d.mts +27 -0
- package/bin/state/iterate-stall.d.mts +27 -0
- package/bin/state/seen-comments.d.mts +62 -0
- package/bin/suggestions/extract.d.mts +8 -0
- package/bin/suggestions/parse.d.mts +48 -0
- package/bin/suggestions/patch.d.mts +14 -0
- package/bin/threads/transcript.d.mts +14 -0
- package/bin/threads/transcript.mjs +4 -0
- package/bin/types/activity.d.mts +30 -0
- package/bin/types/agent-thread.d.mts +9 -0
- package/bin/types/check-annotations.d.mts +14 -0
- package/bin/types/check-classification.d.mts +19 -0
- package/bin/types/github.d.mts +139 -0
- package/bin/types/iterate.d.mts +157 -0
- package/bin/types/protected-run.d.mts +6 -0
- package/bin/types/report.d.mts +176 -0
- package/bin/types/review-thread.d.mts +12 -0
- package/bin/types.d.mts +9 -0
- package/bin/util/markdown.d.mts +1 -0
- package/bin/util/path-segment.d.mts +2 -0
- package/bin/util/sleep.d.mts +1 -0
- package/bin/util/worktree.d.mts +9 -0
- package/bin/util/worktree.mjs +4 -1
- package/package.json +51 -37
- package/plugins/pr-shepherd/.codex-plugin/plugin.json +3 -2
- package/plugins/pr-shepherd/.codex.mcp.json +8 -0
- package/plugins/pr-shepherd/.mcp.json +6 -0
- package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +5 -19
- package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +6 -15
- package/src/classify/types.mts +12 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pr-shepherd",
|
|
3
3
|
"description": "Autonomous PR CI monitor and review-comment resolver for agentic coding tools",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.35.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Jonathan Ong",
|
|
7
7
|
"email": "jonathanrichardong@gmail.com"
|
|
@@ -10,5 +10,6 @@
|
|
|
10
10
|
"repository": "https://github.com/jonathanong/pr-shepherd",
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"keywords": ["github", "pull-request", "ci", "code-review", "automation"],
|
|
13
|
-
"skills": "./plugins/pr-shepherd/skills/"
|
|
13
|
+
"skills": "./plugins/pr-shepherd/skills/",
|
|
14
|
+
"mcpServers": "./plugins/pr-shepherd/.mcp.json"
|
|
14
15
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jonathanong",
|
|
3
|
+
"description": "Jonathan Ong's Grok plugins",
|
|
4
|
+
"owner": {
|
|
5
|
+
"name": "Jonathan Ong",
|
|
6
|
+
"email": "jonathanrichardong@gmail.com"
|
|
7
|
+
},
|
|
8
|
+
"plugins": [
|
|
9
|
+
{
|
|
10
|
+
"name": "pr-shepherd",
|
|
11
|
+
"description": "Autonomous PR CI monitor and review-comment resolver",
|
|
12
|
+
"source": { "type": "local", "path": "./plugins/pr-shepherd" },
|
|
13
|
+
"category": "productivity",
|
|
14
|
+
"homepage": "https://github.com/jonathanong/pr-shepherd"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
package/README.md
CHANGED
|
@@ -6,9 +6,9 @@ The goal is to help an agent carry a planned change to a human-reviewable PR: pa
|
|
|
6
6
|
|
|
7
7
|
## How It Works
|
|
8
8
|
|
|
9
|
-
`pr-shepherd` moves deterministic PR orchestration into a CLI.
|
|
9
|
+
`pr-shepherd` moves deterministic PR orchestration into a local MCP server, with a CLI for shells and CI. Both interfaces fetch the same GitHub state, emit raw-enough context, and return a numbered plan for the calling agent to follow. The agent still decides whether a comment or CI failure requires a code change.
|
|
10
10
|
|
|
11
|
-
The
|
|
11
|
+
The MCP server exposes three tools: `iterate`, `apply`, and `build_suggestion_patch`. `apply` accepts ordered review mutations, file-view mutations, and journal entries. The shipped skills are thin dispatchers for those tools.
|
|
12
12
|
|
|
13
13
|
Each tick returns exactly one action:
|
|
14
14
|
|
|
@@ -30,7 +30,7 @@ Example shape:
|
|
|
30
30
|
|
|
31
31
|
## Review threads
|
|
32
32
|
|
|
33
|
-
### `threadId=PRRT_kwDOSGizTs58XB1L` — `src/commands/iterate/index.mts:42` (@alice)
|
|
33
|
+
### `threadId=PRRT_kwDOSGizTs58XB1L` — `src/commands/iterate/index.mts:42` (@alice · User · MEMBER)
|
|
34
34
|
|
|
35
35
|
> The variable name is misleading.
|
|
36
36
|
|
|
@@ -39,16 +39,16 @@ Example shape:
|
|
|
39
39
|
- `24697658766` — `CI › lint / typecheck / test (22.x)` [conclusion: FAILURE]
|
|
40
40
|
> oxfmt
|
|
41
41
|
|
|
42
|
-
## Post-fix
|
|
42
|
+
## Post-fix plan
|
|
43
43
|
|
|
44
44
|
- base: `main`
|
|
45
|
-
-
|
|
45
|
+
- apply: reply to `PRRT_kwDOSGizTs58XB1L` after the relevant HEAD SHA is visible
|
|
46
46
|
|
|
47
47
|
## Instructions
|
|
48
48
|
|
|
49
|
-
1. Decide for each item under `## Review threads` and `## Failing checks` whether a code change is warranted. If code changes are needed, apply edits, commit,
|
|
49
|
+
1. Decide for each item under `## Review threads` and `## Failing checks` whether a code change is warranted. If code changes are needed, apply edits, commit, and push according to the repository's conventions.
|
|
50
50
|
2. For each failing check under `## Failing checks`: fetch logs when needed and decide whether to rerun or fix.
|
|
51
|
-
3.
|
|
51
|
+
3. Use `apply` with a specific reply/dismiss message and the relevant HEAD SHA.
|
|
52
52
|
4. Stop this iteration.
|
|
53
53
|
```
|
|
54
54
|
|
|
@@ -64,7 +64,7 @@ This system is opinionated and works best with PRs that use required status chec
|
|
|
64
64
|
- Every review thread/comment/review summary is surfaced at least once, even if already outdated, resolved, or minimized; edited items re-surface through seen markers.
|
|
65
65
|
- Draft PRs can be marked ready automatically when clean; disable with `actions.autoMarkReady: false` or `--no-auto-mark-ready`.
|
|
66
66
|
- The CLI never performs git mutations. It emits instructions; the caller commits, rebases, pushes, and handles repository hooks.
|
|
67
|
-
- `
|
|
67
|
+
- `build_suggestion_patch` turns one GitHub suggestion thread into a patch and commit metadata, but never edits the working tree or git history.
|
|
68
68
|
|
|
69
69
|
## Usage
|
|
70
70
|
|
|
@@ -84,7 +84,16 @@ Codex:
|
|
|
84
84
|
/goal $pr-shepherd 42
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
Grok:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
/pr-shepherd # infer PR from current branch
|
|
91
|
+
/pr-shepherd 42
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
MCP clients call `iterate` once per tick, then use `apply` for review/file/journal mutations and `build_suggestion_patch` for an anchored suggestion. `iterate` returns the same structured action data as the CLI, including its review mutation arguments. The client owns recurrence, so this works consistently in Codex, Claude Code, Grok, and any other stdio MCP client.
|
|
95
|
+
|
|
96
|
+
The CLI remains useful for shell workflows. Its canonical polling form is:
|
|
88
97
|
|
|
89
98
|
```sh
|
|
90
99
|
pr-shepherd 42 # poll until non-WAIT or timeout
|
|
@@ -93,48 +102,28 @@ pr-shepherd 42 --quiet-status # print only changed WAIT status snapshot
|
|
|
93
102
|
pr-shepherd 42 --until-terminal # continue through WAIT/MARK_READY until work or terminal state
|
|
94
103
|
pr-shepherd 42 --ready-delay 15m
|
|
95
104
|
pr-shepherd iterate 42 # single tick
|
|
96
|
-
pr-shepherd poll 42 # explicit poll command
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### Resolve Review Items
|
|
100
|
-
|
|
101
|
-
```sh
|
|
102
|
-
pr-shepherd resolve 42 --reply-thread-ids PRRT_abc --message "Renamed the variable for clarity." --require-sha "$(git rev-parse HEAD)"
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Use `pr-shepherd iterate 42` or `pr-shepherd 42` to fetch the next PR action. `resolve` requires at least one action flag and only applies explicit review-state mutations.
|
|
106
|
-
|
|
107
|
-
### Apply One Suggestion Thread
|
|
108
|
-
|
|
109
|
-
```sh
|
|
110
|
-
pr-shepherd commit-suggestion 42 --thread-id PRRT_abc --message "rename value for clarity"
|
|
111
105
|
```
|
|
112
106
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
### Mark Files As Viewed
|
|
116
|
-
|
|
117
|
-
```sh
|
|
118
|
-
pr-shepherd mark-files-as-viewed 42 --tests
|
|
119
|
-
pr-shepherd mark-files-as-viewed 42 src/a.ts --match '^docs/'
|
|
120
|
-
```
|
|
107
|
+
### Apply Review, File, And Journal Changes
|
|
121
108
|
|
|
122
|
-
|
|
109
|
+
Use `apply` with ordered operations to reply/resolve/minimize/dismiss review items, mark changed files viewed, or append an idempotent Shepherd Journal item. Use `build_suggestion_patch` to turn one review suggestion into a validated patch and commit metadata; it never changes the worktree or git history.
|
|
123
110
|
|
|
124
111
|
### Clean Local State
|
|
125
112
|
|
|
126
113
|
`pr-shepherd` stores seen markers, fix-attempt counters, stall fingerprints, ready-delay markers, and logs under `$PR_SHEPHERD_STATE_DIR` (default `$TMPDIR/pr-shepherd-state`).
|
|
127
114
|
|
|
128
115
|
```sh
|
|
129
|
-
pr-shepherd clean current
|
|
130
|
-
pr-shepherd clean repo
|
|
131
|
-
pr-shepherd clean all --dry-run
|
|
132
|
-
pr-shepherd log-file
|
|
116
|
+
pr-shepherd admin clean current
|
|
117
|
+
pr-shepherd admin clean repo
|
|
118
|
+
pr-shepherd admin clean all --dry-run
|
|
119
|
+
pr-shepherd admin log-file
|
|
133
120
|
```
|
|
134
121
|
|
|
135
122
|
## Install
|
|
136
123
|
|
|
137
|
-
|
|
124
|
+
The plugin launches the version-matched `pr-shepherd-mcp` binary from the `pr-shepherd` npm package automatically. Install the `pr-shepherd` CLI separately only when you want the shell interface.
|
|
125
|
+
|
|
126
|
+
To register the MCP server without the plugin, or to wire a local checkout, see [docs/mcp.md](docs/mcp.md).
|
|
138
127
|
|
|
139
128
|
### Claude Code
|
|
140
129
|
|
|
@@ -164,6 +153,30 @@ codex plugin marketplace add ~/.codex/plugin-sources/pr-shepherd
|
|
|
164
153
|
|
|
165
154
|
After adding the marketplace, install/enable the `pr-shepherd` plugin from Codex. The marketplace root must contain `.agents/plugins/marketplace.json` and `plugins/pr-shepherd/`.
|
|
166
155
|
|
|
156
|
+
### Grok
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
grok plugin marketplace add jonathanong/pr-shepherd
|
|
160
|
+
grok plugin install pr-shepherd --trust
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Grok starts a plugin's MCP server only after the plugin is trusted. Confirm with `grok mcp list` or `/mcps`.
|
|
164
|
+
|
|
165
|
+
### MCP server only
|
|
166
|
+
|
|
167
|
+
Any stdio MCP client can run the published binary without installing the plugin:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
claude mcp add --transport stdio --scope user pr-shepherd -- \
|
|
171
|
+
npx --yes --package pr-shepherd@<version> pr-shepherd-mcp
|
|
172
|
+
codex mcp add pr-shepherd -- \
|
|
173
|
+
npx --yes --package pr-shepherd@<version> pr-shepherd-mcp
|
|
174
|
+
grok mcp add pr-shepherd -- \
|
|
175
|
+
npx --yes --package pr-shepherd@<version> pr-shepherd-mcp
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Replace `<version>` with a published version. Full config-file examples, tool schemas, and local-checkout wiring are in [docs/mcp.md](docs/mcp.md).
|
|
179
|
+
|
|
167
180
|
## Configuration
|
|
168
181
|
|
|
169
182
|
Create `.pr-shepherdrc.yml` in your project root or an ancestor directory.
|
|
@@ -175,7 +188,7 @@ iterate:
|
|
|
175
188
|
fixAttemptsPerThread: 5
|
|
176
189
|
stallTimeoutMinutes: 60
|
|
177
190
|
minimizeApprovals: false
|
|
178
|
-
minimizeComments: all # all | bots |
|
|
191
|
+
minimizeComments: all # all | bots | none
|
|
179
192
|
checks:
|
|
180
193
|
ciTriggerEvents:
|
|
181
194
|
- pull_request
|
|
@@ -218,6 +231,10 @@ TypeScript rules are loaded by the runtime's native TypeScript support; keep the
|
|
|
218
231
|
|
|
219
232
|
Ready-to-use examples for common patterns are in [`examples/classification/`](examples/classification/).
|
|
220
233
|
|
|
234
|
+
## Compatibility aliases
|
|
235
|
+
|
|
236
|
+
The legacy CLI subcommands `poll`, `resolve`, `commit-suggestion`, and `mark-files-as-viewed` remain available for compatibility but are no longer advertised as the primary integration. Prefer canonical default polling/`iterate` in a shell and the MCP `iterate`, `apply`, and `build_suggestion_patch` tools in an agent client.
|
|
237
|
+
|
|
221
238
|
## Requirements
|
|
222
239
|
|
|
223
240
|
- Node.js >= 22.18.0, Bun, or Deno
|
package/bin/api.d.mts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type JournalResult } from "./commands/journal/index.mts";
|
|
2
|
+
import { type MarkFilesAsViewedResult } from "./commands/mark-files-as-viewed.mts";
|
|
3
|
+
import type { ResolveResult } from "./comments/resolve.mts";
|
|
4
|
+
import type { CommitSuggestionResult, IterateCommandOptions, IterateResult } from "./types.mts";
|
|
5
|
+
export interface CreatePrShepherdOptions {
|
|
6
|
+
/** Working directory used for git, config, and classification-rule lookups. */
|
|
7
|
+
cwd?: string;
|
|
8
|
+
}
|
|
9
|
+
/** A positive PR number or canonical GitHub pull-request URL. */
|
|
10
|
+
export type PrReference = number | string;
|
|
11
|
+
export type IterateInput = Omit<IterateCommandOptions, "format" | "prNumber"> & {
|
|
12
|
+
pr?: PrReference;
|
|
13
|
+
};
|
|
14
|
+
export interface ReviewMutationsOperation {
|
|
15
|
+
type: "review_mutations";
|
|
16
|
+
resolveThreadIds?: string[];
|
|
17
|
+
replyThreadIds?: string[];
|
|
18
|
+
minimizeCommentIds?: string[];
|
|
19
|
+
dismissReviewIds?: string[];
|
|
20
|
+
/** Required when replying to a thread or dismissing a review. */
|
|
21
|
+
message?: string;
|
|
22
|
+
requireSha?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface MarkFilesViewedOperation {
|
|
25
|
+
type: "mark_files_viewed";
|
|
26
|
+
files?: string[];
|
|
27
|
+
tests?: boolean;
|
|
28
|
+
matchPatterns?: string[];
|
|
29
|
+
}
|
|
30
|
+
export interface AppendJournalOperation {
|
|
31
|
+
type: "append_journal";
|
|
32
|
+
item: string;
|
|
33
|
+
dryRun?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/** Mutations are run in this exact list order after every operation is validated. */
|
|
36
|
+
export type ApplyOperation = ReviewMutationsOperation | MarkFilesViewedOperation | AppendJournalOperation;
|
|
37
|
+
export interface ApplyInput {
|
|
38
|
+
/** PR shared by every operation in this ordered apply request. */
|
|
39
|
+
pr?: PrReference;
|
|
40
|
+
operations: ApplyOperation[];
|
|
41
|
+
}
|
|
42
|
+
export type ApplyOperationResult = {
|
|
43
|
+
type: "review_mutations";
|
|
44
|
+
result: ResolveResult;
|
|
45
|
+
} | {
|
|
46
|
+
type: "mark_files_viewed";
|
|
47
|
+
result: MarkFilesAsViewedResult;
|
|
48
|
+
} | {
|
|
49
|
+
type: "append_journal";
|
|
50
|
+
result: JournalResult;
|
|
51
|
+
};
|
|
52
|
+
export interface ApplyResult {
|
|
53
|
+
operations: ApplyOperationResult[];
|
|
54
|
+
}
|
|
55
|
+
export interface BuildSuggestionPatchInput {
|
|
56
|
+
pr?: PrReference;
|
|
57
|
+
threadId: string;
|
|
58
|
+
message: string;
|
|
59
|
+
description?: string;
|
|
60
|
+
}
|
|
61
|
+
export interface PrShepherd {
|
|
62
|
+
iterate(input?: IterateInput): Promise<IterateResult>;
|
|
63
|
+
apply(input: ApplyInput): Promise<ApplyResult>;
|
|
64
|
+
buildSuggestionPatch(input: BuildSuggestionPatchInput): Promise<CommitSuggestionResult>;
|
|
65
|
+
}
|
|
66
|
+
/** Raised before any API mutation when an input cannot be validated. */
|
|
67
|
+
export declare class PrShepherdValidationError extends Error {
|
|
68
|
+
constructor(message: string);
|
|
69
|
+
}
|
|
70
|
+
/** Raised when a later ordered apply operation fails after earlier operations completed. */
|
|
71
|
+
export declare class PartialApplyError extends Error {
|
|
72
|
+
readonly failedIndex: number;
|
|
73
|
+
readonly completed: ApplyOperationResult[];
|
|
74
|
+
constructor(failedIndex: number, completed: ApplyOperationResult[], cause: unknown);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Creates the programmatic API. The returned object intentionally exposes only
|
|
78
|
+
* read/plan, ordered apply, and suggestion-patch operations.
|
|
79
|
+
*/
|
|
80
|
+
export declare function createPrShepherd(options?: CreatePrShepherdOptions): PrShepherd;
|
package/bin/api.mjs
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/* eslint-disable max-lines */
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { runCommitSuggestion } from "./commands/commit-suggestion.mjs";
|
|
4
|
+
import { runIterate } from "./commands/iterate/index.mjs";
|
|
5
|
+
import { runJournal } from "./commands/journal/index.mjs";
|
|
6
|
+
import { validateJournalItem } from "./commands/journal/transform.mjs";
|
|
7
|
+
import { runMarkFilesAsViewed, } from "./commands/mark-files-as-viewed.mjs";
|
|
8
|
+
import { runResolveMutate } from "./commands/resolve-mutate.mjs";
|
|
9
|
+
import { runWithExecutionCwd } from "./execution-context.mjs";
|
|
10
|
+
import { getRepoInfo } from "./github/client.mjs";
|
|
11
|
+
/** Raised before any API mutation when an input cannot be validated. */
|
|
12
|
+
export class PrShepherdValidationError extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "PrShepherdValidationError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Raised when a later ordered apply operation fails after earlier operations completed. */
|
|
19
|
+
export class PartialApplyError extends Error {
|
|
20
|
+
failedIndex;
|
|
21
|
+
completed;
|
|
22
|
+
constructor(failedIndex, completed, cause) {
|
|
23
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
24
|
+
super(`apply operation ${failedIndex} failed: ${message}`, { cause });
|
|
25
|
+
this.name = "PartialApplyError";
|
|
26
|
+
this.failedIndex = failedIndex;
|
|
27
|
+
this.completed = completed;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates the programmatic API. The returned object intentionally exposes only
|
|
32
|
+
* read/plan, ordered apply, and suggestion-patch operations.
|
|
33
|
+
*/
|
|
34
|
+
export function createPrShepherd(options = {}) {
|
|
35
|
+
const cwd = options.cwd === undefined ? undefined : resolve(options.cwd);
|
|
36
|
+
return Object.freeze({
|
|
37
|
+
iterate(input = {}) {
|
|
38
|
+
const { pr: _pr, ...options } = input;
|
|
39
|
+
return runWithExecutionCwd(cwd, async () => {
|
|
40
|
+
const prNumber = await resolvePrReference(input.pr);
|
|
41
|
+
return runIterate({ ...options, prNumber, format: "json" });
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
apply(input) {
|
|
45
|
+
return runWithExecutionCwd(cwd, async () => {
|
|
46
|
+
validateApplyInput(input);
|
|
47
|
+
const prNumber = await resolvePrReference(input.pr);
|
|
48
|
+
const results = [];
|
|
49
|
+
for (let index = 0; index < input.operations.length; index += 1) {
|
|
50
|
+
const operation = input.operations[index];
|
|
51
|
+
try {
|
|
52
|
+
switch (operation.type) {
|
|
53
|
+
case "review_mutations": {
|
|
54
|
+
const { type: _type, message, ...options } = operation;
|
|
55
|
+
const result = await runResolveMutate({
|
|
56
|
+
...options,
|
|
57
|
+
prNumber,
|
|
58
|
+
dismissMessage: message,
|
|
59
|
+
format: "json",
|
|
60
|
+
});
|
|
61
|
+
results.push({ type: operation.type, result });
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case "mark_files_viewed": {
|
|
65
|
+
const result = await runMarkFilesAsViewed({
|
|
66
|
+
prNumber,
|
|
67
|
+
files: operation.files ?? [],
|
|
68
|
+
tests: operation.tests,
|
|
69
|
+
matchPatterns: operation.matchPatterns,
|
|
70
|
+
format: "json",
|
|
71
|
+
});
|
|
72
|
+
results.push({ type: operation.type, result });
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case "append_journal": {
|
|
76
|
+
const result = await runJournal({
|
|
77
|
+
prNumber,
|
|
78
|
+
rawItem: operation.item,
|
|
79
|
+
dryRun: operation.dryRun ?? false,
|
|
80
|
+
});
|
|
81
|
+
results.push({ type: operation.type, result });
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (results.length === 0)
|
|
88
|
+
throw error;
|
|
89
|
+
throw new PartialApplyError(index, results, error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return { operations: results };
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
buildSuggestionPatch(input) {
|
|
96
|
+
validateSuggestionPatchInput(input);
|
|
97
|
+
const { pr: _pr, ...options } = input;
|
|
98
|
+
return runWithExecutionCwd(cwd, async () => {
|
|
99
|
+
const prNumber = await resolvePrReference(input.pr);
|
|
100
|
+
return runCommitSuggestion({ ...options, prNumber, format: "json" });
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function validateApplyInput(input) {
|
|
106
|
+
if (!input || !Array.isArray(input.operations) || input.operations.length === 0) {
|
|
107
|
+
throw new PrShepherdValidationError("apply requires a non-empty operations array");
|
|
108
|
+
}
|
|
109
|
+
for (const operation of input.operations)
|
|
110
|
+
validateOperation(operation);
|
|
111
|
+
parsePrReference(input.pr);
|
|
112
|
+
}
|
|
113
|
+
function validateOperation(operation) {
|
|
114
|
+
if (!operation || typeof operation !== "object") {
|
|
115
|
+
throw new PrShepherdValidationError("apply operation must be an object");
|
|
116
|
+
}
|
|
117
|
+
switch (operation.type) {
|
|
118
|
+
case "review_mutations":
|
|
119
|
+
validateReviewMutations(operation);
|
|
120
|
+
return;
|
|
121
|
+
case "mark_files_viewed":
|
|
122
|
+
validateMarkFilesViewed(operation);
|
|
123
|
+
return;
|
|
124
|
+
case "append_journal":
|
|
125
|
+
if (typeof operation.item !== "string") {
|
|
126
|
+
throw new PrShepherdValidationError("append_journal.item must be a string");
|
|
127
|
+
}
|
|
128
|
+
if (operation.dryRun !== undefined && typeof operation.dryRun !== "boolean") {
|
|
129
|
+
throw new PrShepherdValidationError("append_journal.dryRun must be a boolean");
|
|
130
|
+
}
|
|
131
|
+
{
|
|
132
|
+
const validation = validateJournalItem(operation.item);
|
|
133
|
+
if (!validation.ok)
|
|
134
|
+
throw new PrShepherdValidationError(validation.error);
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
default:
|
|
138
|
+
throw new PrShepherdValidationError(`Unsupported apply operation: ${JSON.stringify(operation.type)}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function validateReviewMutations(operation) {
|
|
142
|
+
const ids = [
|
|
143
|
+
operation.resolveThreadIds,
|
|
144
|
+
operation.replyThreadIds,
|
|
145
|
+
operation.minimizeCommentIds,
|
|
146
|
+
operation.dismissReviewIds,
|
|
147
|
+
];
|
|
148
|
+
if (!ids.some((value) => value !== undefined && value.length > 0)) {
|
|
149
|
+
throw new PrShepherdValidationError("review_mutations requires at least one mutation ID");
|
|
150
|
+
}
|
|
151
|
+
for (const value of ids)
|
|
152
|
+
validateStringArray(value, "review mutation IDs");
|
|
153
|
+
const needsMessage = (operation.replyThreadIds?.length ?? 0) > 0 || (operation.dismissReviewIds?.length ?? 0) > 0;
|
|
154
|
+
if (needsMessage && (!operation.message || operation.message.trim() === "")) {
|
|
155
|
+
throw new PrShepherdValidationError("review_mutations.message is required for replies or review dismissals");
|
|
156
|
+
}
|
|
157
|
+
if (operation.message !== undefined && typeof operation.message !== "string") {
|
|
158
|
+
throw new PrShepherdValidationError("review_mutations.message must be a string");
|
|
159
|
+
}
|
|
160
|
+
if (operation.requireSha !== undefined && !/^[0-9a-f]{40}$/.test(operation.requireSha)) {
|
|
161
|
+
throw new PrShepherdValidationError("review_mutations.requireSha must be a full 40-character lowercase hex SHA");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function validateMarkFilesViewed(operation) {
|
|
165
|
+
validateStringArray(operation.files, "mark_files_viewed.files");
|
|
166
|
+
validateStringArray(operation.matchPatterns, "mark_files_viewed.matchPatterns");
|
|
167
|
+
if (operation.tests !== undefined && typeof operation.tests !== "boolean") {
|
|
168
|
+
throw new PrShepherdValidationError("mark_files_viewed.tests must be a boolean");
|
|
169
|
+
}
|
|
170
|
+
if ((operation.files?.length ?? 0) === 0 &&
|
|
171
|
+
(operation.matchPatterns?.length ?? 0) === 0 &&
|
|
172
|
+
operation.tests !== true) {
|
|
173
|
+
throw new PrShepherdValidationError("mark_files_viewed requires files, matchPatterns, or tests: true");
|
|
174
|
+
}
|
|
175
|
+
for (const pattern of operation.matchPatterns ?? []) {
|
|
176
|
+
try {
|
|
177
|
+
new RegExp(pattern, "i");
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
181
|
+
throw new PrShepherdValidationError(`Invalid mark_files_viewed match pattern ${JSON.stringify(pattern)}: ${message}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function validateSuggestionPatchInput(input) {
|
|
186
|
+
if (!input || typeof input.threadId !== "string" || input.threadId === "") {
|
|
187
|
+
throw new PrShepherdValidationError("buildSuggestionPatch.threadId is required");
|
|
188
|
+
}
|
|
189
|
+
if (typeof input.message !== "string" || input.message.trim() === "") {
|
|
190
|
+
throw new PrShepherdValidationError("buildSuggestionPatch.message is required and must be non-empty");
|
|
191
|
+
}
|
|
192
|
+
if (input.description !== undefined && typeof input.description !== "string") {
|
|
193
|
+
throw new PrShepherdValidationError("buildSuggestionPatch.description must be a string");
|
|
194
|
+
}
|
|
195
|
+
parsePrReference(input.pr);
|
|
196
|
+
}
|
|
197
|
+
function parsePrReference(pr) {
|
|
198
|
+
if (pr === undefined)
|
|
199
|
+
return {};
|
|
200
|
+
if (typeof pr === "number" && Number.isInteger(pr) && pr > 0)
|
|
201
|
+
return { number: pr };
|
|
202
|
+
if (typeof pr === "string") {
|
|
203
|
+
try {
|
|
204
|
+
const url = new URL(pr);
|
|
205
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
206
|
+
if ((url.protocol === "https:" || url.protocol === "http:") &&
|
|
207
|
+
(url.hostname === "github.com" || url.hostname === "www.github.com") &&
|
|
208
|
+
parts.length === 4 &&
|
|
209
|
+
parts[2] === "pull" &&
|
|
210
|
+
/^[1-9][0-9]*$/.test(parts[3])) {
|
|
211
|
+
return { number: Number(parts[3]), repository: `${parts[0]}/${parts[1]}` };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// Construct the uniform public validation error below.
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
throw new PrShepherdValidationError("pr must be a positive number or a GitHub pull-request URL");
|
|
219
|
+
}
|
|
220
|
+
async function resolvePrReference(pr) {
|
|
221
|
+
const parsed = parsePrReference(pr);
|
|
222
|
+
if (parsed.repository !== undefined) {
|
|
223
|
+
const repo = await getRepoInfo();
|
|
224
|
+
const currentRepository = `${repo.owner}/${repo.name}`;
|
|
225
|
+
if (parsed.repository.toLowerCase() !== currentRepository.toLowerCase()) {
|
|
226
|
+
throw new PrShepherdValidationError(`PR URL repository ${parsed.repository} does not match the configured repository ${currentRepository}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return parsed.number;
|
|
230
|
+
}
|
|
231
|
+
function validateStringArray(value, label) {
|
|
232
|
+
if (value !== undefined &&
|
|
233
|
+
(!Array.isArray(value) || value.some((item) => typeof item !== "string" || item === ""))) {
|
|
234
|
+
throw new PrShepherdValidationError(`${label} must be an array of non-empty strings`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classifies check runs into shepherd categories and filters out irrelevant ones.
|
|
3
|
+
*
|
|
4
|
+
* Rules:
|
|
5
|
+
* 1. Skip checks whose workflow event is NOT `pull_request` or `pull_request_target`.
|
|
6
|
+
* Push-triggered, merge-queue, schedule, and workflow-dispatch runs are irrelevant
|
|
7
|
+
* to PR readiness.
|
|
8
|
+
* 2. Drop checks with `conclusion == SKIPPED` or `conclusion == NEUTRAL` from the
|
|
9
|
+
* pass/fail tally. Report them as "skipped" for transparency but don't block on them.
|
|
10
|
+
* 3. Reclassify `CANCELLED` checks as "superseded" (non-blocking) when a newer run of
|
|
11
|
+
* the same workflow exists on the same commit — this is GitHub's concurrency-group
|
|
12
|
+
* eviction behavior, not a real failure. GitHub branch protection itself resolves
|
|
13
|
+
* required status checks by latest-run-per-name and merges past these; mirroring
|
|
14
|
+
* that here keeps shepherd's verdict aligned with what GitHub will actually allow.
|
|
15
|
+
*/
|
|
16
|
+
import type { CheckRun, ClassifiedCheck } from "../types.mts";
|
|
17
|
+
/**
|
|
18
|
+
* Classify a list of raw check runs into shepherd categories.
|
|
19
|
+
*
|
|
20
|
+
* @param checks Raw check runs from the batch query.
|
|
21
|
+
* @returns Classified checks. "filtered" items were excluded from the tally.
|
|
22
|
+
*/
|
|
23
|
+
export declare function classifyChecks(checks: CheckRun[]): ClassifiedCheck[];
|
|
24
|
+
export interface CiVerdict {
|
|
25
|
+
/** True when all relevant (non-filtered, non-skipped, non-ignored) checks passed. */
|
|
26
|
+
allPassed: boolean;
|
|
27
|
+
/** True when at least one relevant (non-filtered, non-skipped, non-ignored) check exists. */
|
|
28
|
+
hasChecks: boolean;
|
|
29
|
+
/** True when at least one check is still running/queued. */
|
|
30
|
+
anyInProgress: boolean;
|
|
31
|
+
/** True when at least one check failed. */
|
|
32
|
+
anyFailing: boolean;
|
|
33
|
+
/** Names of checks that were filtered out (triggered by non-PR events). */
|
|
34
|
+
filteredNames: string[];
|
|
35
|
+
/** Names of checks suppressed by the user's ignoreChecks config. */
|
|
36
|
+
ignoredNames: string[];
|
|
37
|
+
/** Names of CANCELLED checks superseded by a newer run of the same workflow (concurrency-group eviction). */
|
|
38
|
+
supersededNames: string[];
|
|
39
|
+
}
|
|
40
|
+
/** Compute a high-level CI verdict from a list of classified checks. */
|
|
41
|
+
export declare function getCiVerdict(classified: ClassifiedCheck[]): CiVerdict;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detects check runs that are `CANCELLED` because a newer run of the *same workflow*
|
|
3
|
+
* superseded them on the same commit (concurrency-group eviction), rather than a genuine
|
|
4
|
+
* cancellation. Split out of classify.mts to stay under the file-length cap.
|
|
5
|
+
*/
|
|
6
|
+
import type { CheckRun } from "../types.mts";
|
|
7
|
+
/**
|
|
8
|
+
* Grouping key is `workflowId ?? workflowName` — the numeric GitHub Actions workflow database
|
|
9
|
+
* ID when available, falling back to the display name. Checks with neither a workflow identity
|
|
10
|
+
* nor a numeric `runId` (status contexts, startup-failure synthetics) never participate: they
|
|
11
|
+
* can neither be marked superseded nor count as evidence of a newer run.
|
|
12
|
+
*
|
|
13
|
+
* A check is superseded iff its own conclusion is `CANCELLED` and some other check sharing its
|
|
14
|
+
* workflow key has a strictly greater `runId`. The newest run for a workflow is therefore never
|
|
15
|
+
* superseded, even if it is itself cancelled — that case stays "failing" so the agent can decide
|
|
16
|
+
* whether to rerun it.
|
|
17
|
+
*
|
|
18
|
+
* @returns Indices into `checks` (not object identities, since check-run objects are not
|
|
19
|
+
* deduplicated by reference elsewhere) that should be reclassified as "superseded".
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildSupersededIndices(checks: CheckRun[]): Set<number>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CheckRun, ClassifiedCheck, TriagedCheck } from "../types.mts";
|
|
2
|
+
import type { RepoInfo } from "../github/client.mts";
|
|
3
|
+
export declare function triageFailingChecks(failingChecks: ClassifiedCheck[], repo: RepoInfo): Promise<TriagedCheck[]>;
|
|
4
|
+
export declare function fetchStartupFailureChecks(repo: RepoInfo, headSha: string, prNumber: number): Promise<CheckRun[]>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BatchPrData } from "../types.mts";
|
|
2
|
+
import type { LoadedRule } from "./loader.mts";
|
|
3
|
+
export interface ClassifyIndex {
|
|
4
|
+
suppressedIds: Set<string>;
|
|
5
|
+
autoResolveIds: Set<string>;
|
|
6
|
+
}
|
|
7
|
+
export interface BatchPartition {
|
|
8
|
+
suppressedCommentIds: Set<string>;
|
|
9
|
+
suppressedThreadIds: Set<string>;
|
|
10
|
+
suppressedReviewSummaryIds: Set<string>;
|
|
11
|
+
suppressedChangesRequestedIds: Set<string>;
|
|
12
|
+
ruleAutoResolveCommentIds: string[];
|
|
13
|
+
ruleAutoResolveThreadIds: string[];
|
|
14
|
+
/** COMMENTED review summary IDs — minimized without surfacing to the agent. */
|
|
15
|
+
ruleAutoResolveReviewSummaryIds: string[];
|
|
16
|
+
}
|
|
17
|
+
export declare function buildClassifyIndex(rules: LoadedRule[], batch: BatchPrData): ClassifyIndex;
|
|
18
|
+
export declare function partitionBatch(index: ClassifyIndex, batch: BatchPrData): BatchPartition;
|
package/bin/classify/apply.mjs
CHANGED
|
@@ -26,6 +26,7 @@ function threadToItem(t) {
|
|
|
26
26
|
id: t.id,
|
|
27
27
|
author: t.author,
|
|
28
28
|
authorType: t.authorType,
|
|
29
|
+
...(t.authorAssociation !== undefined && { authorAssociation: t.authorAssociation }),
|
|
29
30
|
body: t.body,
|
|
30
31
|
url: t.url,
|
|
31
32
|
path: t.path,
|
|
@@ -37,6 +38,7 @@ function commentToItem(c) {
|
|
|
37
38
|
id: c.id,
|
|
38
39
|
author: c.author,
|
|
39
40
|
authorType: c.authorType,
|
|
41
|
+
...(c.authorAssociation !== undefined && { authorAssociation: c.authorAssociation }),
|
|
40
42
|
body: c.body,
|
|
41
43
|
url: c.url,
|
|
42
44
|
};
|
|
@@ -47,6 +49,7 @@ function reviewSummaryToItem(r) {
|
|
|
47
49
|
id: r.id,
|
|
48
50
|
author: r.author,
|
|
49
51
|
authorType: r.authorType,
|
|
52
|
+
...(r.authorAssociation !== undefined && { authorAssociation: r.authorAssociation }),
|
|
50
53
|
body: r.body,
|
|
51
54
|
};
|
|
52
55
|
}
|
|
@@ -56,6 +59,7 @@ function changesRequestedToItem(r) {
|
|
|
56
59
|
id: r.id,
|
|
57
60
|
author: r.author,
|
|
58
61
|
authorType: r.authorType,
|
|
62
|
+
...(r.authorAssociation !== undefined && { authorAssociation: r.authorAssociation }),
|
|
59
63
|
body: r.body,
|
|
60
64
|
};
|
|
61
65
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ClassifyRule } from "./types.mts";
|
|
2
|
+
export interface LoadedRule {
|
|
3
|
+
name: string;
|
|
4
|
+
file: string;
|
|
5
|
+
rule: ClassifyRule;
|
|
6
|
+
}
|
|
7
|
+
export declare function discoverRuleFiles(cwd: string): string[];
|
|
8
|
+
export declare function loadRules(files: string[]): Promise<LoadedRule[]>;
|
|
9
|
+
/** Reset the rule cache — for use in tests. */
|
|
10
|
+
export declare function _resetRuleCache(): void;
|