prq-cli 0.6.0 → 0.8.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/README.md +146 -57
- package/dist/bin/prq.js +105 -61
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
PR Queue — see what code reviews need your attention.
|
|
6
6
|
|
|
7
|
-
A CLI tool that
|
|
7
|
+
A CLI tool that shows you a categorized view of PRs that need action — then lets you act on them with whatever tools you already use. PRQ is the queue. You bring the workflow.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -17,83 +17,185 @@ Requires [GitHub CLI](https://cli.github.com/) (`gh`) to be authenticated.
|
|
|
17
17
|
## Quick Start
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
# See your review queue
|
|
20
|
+
# See your review queue (interactive by default)
|
|
21
21
|
prq
|
|
22
22
|
|
|
23
|
-
#
|
|
24
|
-
prq -
|
|
23
|
+
# Non-interactive / plain text
|
|
24
|
+
prq --no-interactive
|
|
25
|
+
|
|
26
|
+
# Act on a PR
|
|
27
|
+
prq review 482
|
|
28
|
+
prq open 482
|
|
29
|
+
prq nudge 482
|
|
25
30
|
```
|
|
26
31
|
|
|
27
32
|
## Commands
|
|
28
33
|
|
|
29
34
|
### `prq status` (default)
|
|
30
35
|
|
|
31
|
-
Shows PRs needing your attention
|
|
36
|
+
Shows PRs needing your attention in four categories:
|
|
32
37
|
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
38
|
+
- **◆ Needs Re-review** — new commits pushed after your review
|
|
39
|
+
- **● Requested** — you're a requested reviewer
|
|
40
|
+
- **○ Stale** — no activity for N days
|
|
41
|
+
- **◇ Your PRs Waiting** — waiting on someone else
|
|
37
42
|
|
|
38
43
|
```bash
|
|
39
|
-
prq #
|
|
44
|
+
prq # interactive mode (default)
|
|
40
45
|
prq status --repos org/repo1 org/repo2 # specific repos
|
|
41
|
-
prq status --stale-days 7 # custom
|
|
42
|
-
prq status --json # machine-readable
|
|
43
|
-
prq
|
|
46
|
+
prq status --stale-days 7 # custom threshold
|
|
47
|
+
prq status --json # machine-readable
|
|
48
|
+
prq --no-interactive # plain text output
|
|
44
49
|
```
|
|
45
50
|
|
|
46
|
-
### Interactive Mode
|
|
51
|
+
### Interactive Mode (default)
|
|
52
|
+
|
|
53
|
+
Interactive mode is the default when running in a terminal. Navigate your queue with keyboard shortcuts:
|
|
47
54
|
|
|
48
|
-
|
|
55
|
+
| Key | Action |
|
|
56
|
+
|-----|--------|
|
|
57
|
+
| ↑↓ | Navigate between PRs |
|
|
58
|
+
| r | Review — open files changed |
|
|
59
|
+
| o | Open — open PR in browser |
|
|
60
|
+
| n | Nudge — post a comment |
|
|
61
|
+
| c | Copy URL to clipboard |
|
|
62
|
+
| a | Actions — open menu with all actions |
|
|
63
|
+
| q | Quit |
|
|
49
64
|
|
|
50
|
-
-
|
|
51
|
-
- **r** review — open files changed tab
|
|
52
|
-
- **o** open — open PR in browser
|
|
53
|
-
- **n** nudge — post a comment
|
|
54
|
-
- **c** copy URL to clipboard
|
|
55
|
-
- **q** quit
|
|
65
|
+
Press **a** to open the actions menu, which lists all actions (built-in and custom from your config). Press **1-9** to run an action, or **q** to dismiss.
|
|
56
66
|
|
|
57
|
-
### `prq open <identifier>`
|
|
67
|
+
### `prq open/review/nudge <identifier>`
|
|
58
68
|
|
|
59
|
-
|
|
69
|
+
Act on PRs by number, `org/repo#number`, or full URL:
|
|
60
70
|
|
|
61
71
|
```bash
|
|
62
|
-
prq open 482 #
|
|
63
|
-
prq
|
|
64
|
-
prq
|
|
72
|
+
prq open 482 # open in browser
|
|
73
|
+
prq review 482 # open files changed
|
|
74
|
+
prq nudge 482 # post a comment
|
|
75
|
+
prq nudge 482 --yes --message "Update?" # skip confirmation
|
|
65
76
|
```
|
|
66
77
|
|
|
67
|
-
### `prq
|
|
78
|
+
### `prq run <action> <identifier>`
|
|
68
79
|
|
|
69
|
-
|
|
80
|
+
Run any custom action you've defined:
|
|
70
81
|
|
|
71
82
|
```bash
|
|
72
|
-
prq
|
|
73
|
-
prq review
|
|
83
|
+
prq run checkout 482
|
|
84
|
+
prq run ai-review 482
|
|
74
85
|
```
|
|
75
86
|
|
|
76
|
-
### `prq
|
|
87
|
+
### `prq skill`
|
|
77
88
|
|
|
78
|
-
|
|
89
|
+
Install the `/prq` skill for Claude Code:
|
|
79
90
|
|
|
80
91
|
```bash
|
|
81
|
-
prq
|
|
82
|
-
prq
|
|
83
|
-
prq nudge 482 --message "Any updates?" # custom message
|
|
92
|
+
prq skill # install in current project
|
|
93
|
+
prq skill --global # install globally
|
|
84
94
|
```
|
|
85
95
|
|
|
86
|
-
|
|
96
|
+
## Pluggable Actions
|
|
97
|
+
|
|
98
|
+
PRQ doesn't force a workflow. Every action is a configurable shell command template — inline commands or scripts. Override the defaults or add your own in `.prqrc.json`.
|
|
99
|
+
|
|
100
|
+
Actions run with full terminal control. When you trigger an action, prq suspends its TUI, the command takes over the screen (interactive tools like Claude Code work as normal), and prq resumes when the command exits.
|
|
101
|
+
|
|
102
|
+
### Use Claude Code for reviews
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"actions": {
|
|
107
|
+
"review": "claude '/review {url}'"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Now `prq review 482` opens an interactive Claude Code session.
|
|
113
|
+
|
|
114
|
+
### Use Codex for reviews
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"actions": {
|
|
119
|
+
"review": "codex exec --full-auto 'review the PR at {url}'"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Use a script for complex workflows
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"actions": {
|
|
129
|
+
"review": "./scripts/review.sh {number} {url}"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The script handles its own logic — session management, resuming, branching, whatever you need.
|
|
135
|
+
|
|
136
|
+
### Use gh CLI to checkout
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"actions": {
|
|
141
|
+
"checkout": "gh pr checkout {number} --repo {owner}/{repo}"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Then `prq run checkout 482`.
|
|
147
|
+
|
|
148
|
+
### Just open in browser (default)
|
|
149
|
+
|
|
150
|
+
With no config, `prq review` opens the files changed tab and `prq open` opens the PR page. Zero setup needed.
|
|
151
|
+
|
|
152
|
+
### Template variables
|
|
153
|
+
|
|
154
|
+
| Variable | Example |
|
|
155
|
+
|----------|---------|
|
|
156
|
+
| `{url}` | `https://github.com/org/repo/pull/482` |
|
|
157
|
+
| `{number}` | `482` |
|
|
158
|
+
| `{owner}` | `org` |
|
|
159
|
+
| `{repo}` | `repo` |
|
|
160
|
+
| `{fullRepo}` | `org/repo` |
|
|
161
|
+
| `{title}` | `fix: handle edge case` |
|
|
162
|
+
| `{author}` | `alice` |
|
|
163
|
+
| `{days}` | `5` |
|
|
164
|
+
| `{category}` | `needs-re-review` |
|
|
165
|
+
|
|
166
|
+
## Agent & Automation
|
|
87
167
|
|
|
88
|
-
|
|
168
|
+
PRQ is fully scriptable with `--json` output and `--yes` flags:
|
|
89
169
|
|
|
90
170
|
```bash
|
|
91
|
-
|
|
171
|
+
# Agent reads the queue
|
|
172
|
+
prq status --json
|
|
173
|
+
|
|
174
|
+
# Agent nudges all stale PRs
|
|
175
|
+
prq status --json | jq -r '.prs[] | select(.category == "stale") | .number' \
|
|
176
|
+
| xargs -I{} prq nudge {} --yes
|
|
177
|
+
|
|
178
|
+
# Claude Code cron
|
|
179
|
+
prq status --json | claude -p "Review needs-re-review PRs older than 7 days"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Claude Code Skill
|
|
183
|
+
|
|
184
|
+
Install the `/prq` skill to use PRQ inside Claude Code sessions:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
prq skill --global
|
|
92
188
|
```
|
|
93
189
|
|
|
94
|
-
|
|
190
|
+
Then in Claude Code:
|
|
95
191
|
|
|
96
|
-
|
|
192
|
+
```
|
|
193
|
+
/prq → show queue, ask what to do
|
|
194
|
+
"review 2439" → dispatches to your configured review action
|
|
195
|
+
"nudge all stale PRs" → batch nudge
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The skill reads your `.prqrc.json` actions — if you have `/review` configured, it uses that. If not, it falls back to opening the browser.
|
|
97
199
|
|
|
98
200
|
## Configuration
|
|
99
201
|
|
|
@@ -103,33 +205,20 @@ Config is loaded in this order (later overrides earlier):
|
|
|
103
205
|
2. `.prqrc.json` — per-project config
|
|
104
206
|
3. CLI flags
|
|
105
207
|
|
|
106
|
-
|
|
208
|
+
Full example:
|
|
107
209
|
|
|
108
210
|
```json
|
|
109
211
|
{
|
|
110
212
|
"repos": ["org/repo1", "org/repo2"],
|
|
111
213
|
"staleDays": 5,
|
|
112
214
|
"actions": {
|
|
113
|
-
"review": "claude
|
|
114
|
-
"checkout": "gh pr checkout {number} --repo {owner}/{repo}"
|
|
215
|
+
"review": "claude '/review {url}'",
|
|
216
|
+
"checkout": "gh pr checkout {number} --repo {owner}/{repo}",
|
|
217
|
+
"approve": "gh pr review {number} --repo {owner}/{repo} --approve"
|
|
115
218
|
}
|
|
116
219
|
}
|
|
117
220
|
```
|
|
118
221
|
|
|
119
|
-
### Custom Actions
|
|
120
|
-
|
|
121
|
-
Actions are shell command templates with variables:
|
|
122
|
-
|
|
123
|
-
- `{url}` — full PR URL
|
|
124
|
-
- `{number}` — PR number
|
|
125
|
-
- `{owner}` — repo owner
|
|
126
|
-
- `{repo}` — repo name
|
|
127
|
-
- `{title}` — PR title
|
|
128
|
-
- `{author}` — PR author
|
|
129
|
-
- `{days}` — days since last activity
|
|
130
|
-
|
|
131
|
-
Default actions (`open`, `review`, `nudge`) can be overridden. Custom actions are available via `prq run <action>` and in interactive mode.
|
|
132
|
-
|
|
133
222
|
## License
|
|
134
223
|
|
|
135
224
|
MIT
|
package/dist/bin/prq.js
CHANGED
|
@@ -6424,7 +6424,7 @@ function getAction(name, config) {
|
|
|
6424
6424
|
function listActions(config) {
|
|
6425
6425
|
return { ...DEFAULT_ACTIONS, ...config.actions };
|
|
6426
6426
|
}
|
|
6427
|
-
function buildContext(pr) {
|
|
6427
|
+
function buildContext(pr, category = "") {
|
|
6428
6428
|
const days = Math.floor((Date.now() - new Date(pr.updatedAt || Date.now()).getTime()) / 86400000);
|
|
6429
6429
|
return {
|
|
6430
6430
|
url: pr.url,
|
|
@@ -6434,7 +6434,8 @@ function buildContext(pr) {
|
|
|
6434
6434
|
fullRepo: `${pr.owner}/${pr.repo}`,
|
|
6435
6435
|
title: pr.title,
|
|
6436
6436
|
author: pr.author,
|
|
6437
|
-
days
|
|
6437
|
+
days,
|
|
6438
|
+
category
|
|
6438
6439
|
};
|
|
6439
6440
|
}
|
|
6440
6441
|
function interpolate(template, context) {
|
|
@@ -6732,7 +6733,8 @@ function toResolvedPR(pr) {
|
|
|
6732
6733
|
updatedAt: pr.updatedAt
|
|
6733
6734
|
};
|
|
6734
6735
|
}
|
|
6735
|
-
function render(
|
|
6736
|
+
function render(state) {
|
|
6737
|
+
const { result, selectedIndex, message, actionMenu } = state;
|
|
6736
6738
|
process.stdout.write("\x1B[2J\x1B[H");
|
|
6737
6739
|
const lines = [];
|
|
6738
6740
|
lines.push(source_default.bold(` PRQ Status for ${result.user}`));
|
|
@@ -6775,8 +6777,20 @@ function render(result, selectedIndex, message) {
|
|
|
6775
6777
|
}
|
|
6776
6778
|
lines.push("");
|
|
6777
6779
|
lines.push(source_default.dim(` ${"─".repeat(50)}`));
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
+
if (actionMenu) {
|
|
6781
|
+
const pr = result.prs[selectedIndex];
|
|
6782
|
+
lines.push("");
|
|
6783
|
+
lines.push(` ${source_default.bold("Actions")} for ${source_default.white(`#${pr.number}`)}`);
|
|
6784
|
+
lines.push("");
|
|
6785
|
+
for (let i = 0;i < actionMenu.length; i++) {
|
|
6786
|
+
lines.push(` ${source_default.white(String(i + 1))}. ${actionMenu[i].name}`);
|
|
6787
|
+
}
|
|
6788
|
+
lines.push("");
|
|
6789
|
+
lines.push(` ${source_default.dim("1-9")} run action ${source_default.white("q")} back`);
|
|
6790
|
+
} else {
|
|
6791
|
+
lines.push("");
|
|
6792
|
+
lines.push(` ${source_default.dim("↑↓")} navigate ${source_default.white("r")} review ${source_default.white("o")} open ${source_default.white("n")} nudge ${source_default.white("c")} copy url ${source_default.white("a")} actions ${source_default.white("q")} quit`);
|
|
6793
|
+
}
|
|
6780
6794
|
if (message) {
|
|
6781
6795
|
lines.push("");
|
|
6782
6796
|
lines.push(` ${message}`);
|
|
@@ -6784,6 +6798,37 @@ function render(result, selectedIndex, message) {
|
|
|
6784
6798
|
process.stdout.write(lines.join(`
|
|
6785
6799
|
`));
|
|
6786
6800
|
}
|
|
6801
|
+
function suspend() {
|
|
6802
|
+
process.stdin.setRawMode(false);
|
|
6803
|
+
process.stdin.pause();
|
|
6804
|
+
process.stdin.removeAllListeners("data");
|
|
6805
|
+
process.stdout.write("\x1B[?25h\x1B[2J\x1B[H");
|
|
6806
|
+
}
|
|
6807
|
+
function resume(state, onData) {
|
|
6808
|
+
process.stdin.setRawMode(true);
|
|
6809
|
+
process.stdin.resume();
|
|
6810
|
+
process.stdin.setEncoding("utf8");
|
|
6811
|
+
process.stdout.write("\x1B[?25l");
|
|
6812
|
+
process.stdin.on("data", onData);
|
|
6813
|
+
render(state);
|
|
6814
|
+
}
|
|
6815
|
+
async function runAction(actionName, template, pr, state, onData) {
|
|
6816
|
+
const context = buildContext(toResolvedPR(pr), pr.category);
|
|
6817
|
+
const cmd = interpolate(template, context);
|
|
6818
|
+
suspend();
|
|
6819
|
+
process.stdout.write(source_default.dim(`
|
|
6820
|
+
running ${actionName} on ${pr.repo}#${pr.number}...
|
|
6821
|
+
|
|
6822
|
+
`));
|
|
6823
|
+
try {
|
|
6824
|
+
await executeCommand(cmd);
|
|
6825
|
+
resume(state, onData);
|
|
6826
|
+
return source_default.green(`${actionName}: ${pr.repo}#${pr.number}`);
|
|
6827
|
+
} catch {
|
|
6828
|
+
resume(state, onData);
|
|
6829
|
+
return source_default.red(`${actionName} failed`);
|
|
6830
|
+
}
|
|
6831
|
+
}
|
|
6787
6832
|
async function interactiveMode(result, config) {
|
|
6788
6833
|
if (result.prs.length === 0) {
|
|
6789
6834
|
console.log(source_default.green(`
|
|
@@ -6791,84 +6836,73 @@ async function interactiveMode(result, config) {
|
|
|
6791
6836
|
`));
|
|
6792
6837
|
return;
|
|
6793
6838
|
}
|
|
6794
|
-
let selectedIndex = 0;
|
|
6795
|
-
let message = "";
|
|
6796
6839
|
const total = result.prs.length;
|
|
6840
|
+
const allActions = listActions(config);
|
|
6841
|
+
const state = {
|
|
6842
|
+
result,
|
|
6843
|
+
selectedIndex: 0,
|
|
6844
|
+
message: "",
|
|
6845
|
+
actionMenu: null
|
|
6846
|
+
};
|
|
6797
6847
|
if (!process.stdin.isTTY) {
|
|
6798
6848
|
process.stdout.write(`Interactive mode requires a terminal. Use prq status instead.
|
|
6799
6849
|
`);
|
|
6800
6850
|
return;
|
|
6801
6851
|
}
|
|
6802
|
-
process.stdin.setRawMode(true);
|
|
6803
|
-
process.stdin.resume();
|
|
6804
|
-
process.stdin.setEncoding("utf8");
|
|
6805
|
-
process.stdout.write("\x1B[?25l");
|
|
6806
|
-
render(result, selectedIndex, message);
|
|
6807
6852
|
return new Promise((resolve) => {
|
|
6808
|
-
const
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6853
|
+
const onData = async (key) => {
|
|
6854
|
+
const pr = result.prs[state.selectedIndex];
|
|
6855
|
+
if (state.actionMenu) {
|
|
6856
|
+
if (key === "q" || key === "\x1B" || key === "a") {
|
|
6857
|
+
state.actionMenu = null;
|
|
6858
|
+
state.message = "";
|
|
6859
|
+
} else if (key === "\x03") {
|
|
6860
|
+
suspend();
|
|
6861
|
+
resolve();
|
|
6862
|
+
return;
|
|
6863
|
+
} else {
|
|
6864
|
+
const idx = parseInt(key, 10);
|
|
6865
|
+
if (idx >= 1 && idx <= state.actionMenu.length) {
|
|
6866
|
+
const action = state.actionMenu[idx - 1];
|
|
6867
|
+
state.message = await runAction(action.name, action.template, pr, state, onData);
|
|
6868
|
+
state.actionMenu = null;
|
|
6869
|
+
}
|
|
6870
|
+
}
|
|
6871
|
+
render(state);
|
|
6872
|
+
return;
|
|
6873
|
+
}
|
|
6816
6874
|
switch (key) {
|
|
6817
6875
|
case "q":
|
|
6818
6876
|
case "\x03":
|
|
6819
|
-
|
|
6877
|
+
suspend();
|
|
6820
6878
|
resolve();
|
|
6821
6879
|
return;
|
|
6822
6880
|
case "\x1B[A":
|
|
6823
|
-
selectedIndex = Math.max(0, selectedIndex - 1);
|
|
6824
|
-
message = "";
|
|
6881
|
+
state.selectedIndex = Math.max(0, state.selectedIndex - 1);
|
|
6882
|
+
state.message = "";
|
|
6825
6883
|
break;
|
|
6826
6884
|
case "\x1B[B":
|
|
6827
|
-
selectedIndex = Math.min(total - 1, selectedIndex + 1);
|
|
6828
|
-
message = "";
|
|
6885
|
+
state.selectedIndex = Math.min(total - 1, state.selectedIndex + 1);
|
|
6886
|
+
state.message = "";
|
|
6829
6887
|
break;
|
|
6830
6888
|
case "o": {
|
|
6831
|
-
const template =
|
|
6889
|
+
const template = allActions.open;
|
|
6832
6890
|
if (template) {
|
|
6833
|
-
|
|
6834
|
-
message = source_default.dim(`opening ${pr.repo}#${pr.number}...`);
|
|
6835
|
-
render(result, selectedIndex, message);
|
|
6836
|
-
try {
|
|
6837
|
-
await executeCommand(cmd);
|
|
6838
|
-
message = source_default.green(`opened ${pr.repo}#${pr.number}`);
|
|
6839
|
-
} catch {
|
|
6840
|
-
message = source_default.red("failed to open");
|
|
6841
|
-
}
|
|
6891
|
+
state.message = await runAction("open", template, pr, state, onData);
|
|
6842
6892
|
}
|
|
6843
6893
|
break;
|
|
6844
6894
|
}
|
|
6845
6895
|
case "r": {
|
|
6846
|
-
const template =
|
|
6896
|
+
const template = allActions.review;
|
|
6847
6897
|
if (template) {
|
|
6848
|
-
|
|
6849
|
-
message = source_default.dim(`opening review for ${pr.repo}#${pr.number}...`);
|
|
6850
|
-
render(result, selectedIndex, message);
|
|
6851
|
-
try {
|
|
6852
|
-
await executeCommand(cmd);
|
|
6853
|
-
message = source_default.green(`opened review for ${pr.repo}#${pr.number}`);
|
|
6854
|
-
} catch {
|
|
6855
|
-
message = source_default.red("failed to open review");
|
|
6856
|
-
}
|
|
6898
|
+
state.message = await runAction("review", template, pr, state, onData);
|
|
6857
6899
|
}
|
|
6858
6900
|
break;
|
|
6859
6901
|
}
|
|
6860
6902
|
case "n": {
|
|
6861
|
-
const template =
|
|
6903
|
+
const template = allActions.nudge;
|
|
6862
6904
|
if (template) {
|
|
6863
|
-
|
|
6864
|
-
message = source_default.dim(`nudging ${pr.repo}#${pr.number}...`);
|
|
6865
|
-
render(result, selectedIndex, message);
|
|
6866
|
-
try {
|
|
6867
|
-
await executeCommand(cmd);
|
|
6868
|
-
message = source_default.green(`nudged ${pr.repo}#${pr.number}`);
|
|
6869
|
-
} catch {
|
|
6870
|
-
message = source_default.red("failed to nudge");
|
|
6871
|
-
}
|
|
6905
|
+
state.message = await runAction("nudge", template, pr, state, onData);
|
|
6872
6906
|
}
|
|
6873
6907
|
break;
|
|
6874
6908
|
}
|
|
@@ -6877,17 +6911,27 @@ async function interactiveMode(result, config) {
|
|
|
6877
6911
|
try {
|
|
6878
6912
|
const proc = process.platform === "darwin" ? "pbcopy" : process.platform === "linux" ? "xclip -selection clipboard" : "clip";
|
|
6879
6913
|
await executeCommand(`echo "${url}" | ${proc}`);
|
|
6880
|
-
message = source_default.green("url copied");
|
|
6914
|
+
state.message = source_default.green("url copied");
|
|
6881
6915
|
} catch {
|
|
6882
|
-
message = source_default.dim(url);
|
|
6916
|
+
state.message = source_default.dim(url);
|
|
6883
6917
|
}
|
|
6884
6918
|
break;
|
|
6885
6919
|
}
|
|
6920
|
+
case "a": {
|
|
6921
|
+
const entries = Object.entries(allActions);
|
|
6922
|
+
state.actionMenu = entries.map(([name, template]) => ({
|
|
6923
|
+
name,
|
|
6924
|
+
template
|
|
6925
|
+
}));
|
|
6926
|
+
state.message = "";
|
|
6927
|
+
break;
|
|
6928
|
+
}
|
|
6886
6929
|
default:
|
|
6887
6930
|
break;
|
|
6888
6931
|
}
|
|
6889
|
-
render(
|
|
6890
|
-
}
|
|
6932
|
+
render(state);
|
|
6933
|
+
};
|
|
6934
|
+
resume(state, onData);
|
|
6891
6935
|
});
|
|
6892
6936
|
}
|
|
6893
6937
|
|
|
@@ -11009,12 +11053,12 @@ function getVersion() {
|
|
|
11009
11053
|
function createCLI() {
|
|
11010
11054
|
const program2 = new Command;
|
|
11011
11055
|
program2.name("prq").description("PR Queue — see what code reviews need your attention").version(getVersion());
|
|
11012
|
-
program2.command("status", { isDefault: true }).description("Show PRs needing your attention").option("-r, --repos <repos...>", "Filter to specific repos (owner/name)").option("-s, --stale-days <days>", "Days of inactivity to consider stale", "3").option("--json", "Output as JSON").option("-
|
|
11056
|
+
program2.command("status", { isDefault: true }).description("Show PRs needing your attention").option("-r, --repos <repos...>", "Filter to specific repos (owner/name)").option("-s, --stale-days <days>", "Days of inactivity to consider stale", "3").option("--json", "Output as JSON").option("--no-interactive", "Disable interactive mode").action(async (opts) => {
|
|
11013
11057
|
const config = loadConfig({
|
|
11014
11058
|
repos: opts.repos,
|
|
11015
11059
|
staleDays: opts.staleDays ? parseInt(opts.staleDays, 10) : undefined
|
|
11016
11060
|
});
|
|
11017
|
-
await statusCommand(config, opts.json ?? false, opts.interactive ??
|
|
11061
|
+
await statusCommand(config, opts.json ?? false, opts.interactive ?? true);
|
|
11018
11062
|
});
|
|
11019
11063
|
program2.command("open <identifier>").description("Open a PR in the browser").action(async (identifier) => {
|
|
11020
11064
|
const config = loadConfig({});
|