prq-cli 0.5.0 → 0.7.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.
Files changed (3) hide show
  1. package/README.md +129 -56
  2. package/dist/bin/prq.js +198 -46
  3. 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 queries GitHub and shows you a categorized view of PRs that need action. No more missing review requests because someone forgot to re-request, no more stale PRs sitting idle.
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,169 @@ 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
- # Interactive mode navigate with arrow keys, act with shortcuts
24
- prq -i
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, grouped into four categories:
36
+ Shows PRs needing your attention in four categories:
32
37
 
33
- - **Needs Re-review** — you left a review, but new commits were pushed after
34
- - **Requested Reviews** — you're a requested reviewer and haven't reviewed yet
35
- - **Stale** — PRs you're involved in with no activity for N days
36
- - **Your PRs Waiting** — PRs you authored that are waiting on someone else
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 # all repos you have access to
44
+ prq # interactive mode (default)
40
45
  prq status --repos org/repo1 org/repo2 # specific repos
41
- prq status --stale-days 7 # custom stale threshold
42
- prq status --json # machine-readable output
43
- prq status -i # interactive mode
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)
47
52
 
48
- Run `prq -i` to navigate your queue with keyboard shortcuts:
53
+ Interactive mode is the default when running in a terminal. Navigate your queue with keyboard shortcuts:
49
54
 
50
- - **↑↓** navigate between PRs
51
- - **r** review — open files changed tab
52
- - **o** open open PR in browser
53
- - **n** nudgepost a comment
54
- - **c** copy URL to clipboard
55
- - **q** quit
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 |
56
64
 
57
- ### `prq open <identifier>`
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.
58
66
 
59
- Open a PR in the browser.
67
+ ### `prq open/review/nudge <identifier>`
68
+
69
+ Act on PRs by number, `org/repo#number`, or full URL:
60
70
 
61
71
  ```bash
62
- prq open 482 # searches your queue for PR #482
63
- prq open superdoc-dev/superdoc#482 # opens directly
64
- prq open https://github.com/org/repo/pull/482
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 review <identifier>`
78
+ ### `prq run <action> <identifier>`
68
79
 
69
- Open a PR's "Files changed" tab for review.
80
+ Run any custom action you've defined:
70
81
 
71
82
  ```bash
72
- prq review 482
73
- prq review superdoc-dev/superdoc#482
83
+ prq run checkout 482
84
+ prq run ai-review 482
74
85
  ```
75
86
 
76
- ### `prq nudge <identifier>`
87
+ ### `prq skill`
77
88
 
78
- Post a comment on a PR asking if it's still active.
89
+ Install the `/prq` skill for Claude Code:
79
90
 
80
91
  ```bash
81
- prq nudge 482 # confirm before posting
82
- prq nudge 482 --yes # skip confirmation
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
- ### `prq run <action> <identifier>`
96
+ ## Pluggable Actions
97
+
98
+ PRQ doesn't force a workflow. Every action is a configurable shell command template. Override the defaults or add your own in `.prqrc.json`:
99
+
100
+ ### Use Claude Code for reviews
101
+
102
+ ```json
103
+ {
104
+ "actions": {
105
+ "review": "claude -p '/review {url}'"
106
+ }
107
+ }
108
+ ```
109
+
110
+ Now `prq review 482` dispatches to Claude Code.
111
+
112
+ ### Use Codex for reviews
113
+
114
+ ```json
115
+ {
116
+ "actions": {
117
+ "review": "codex exec --full-auto 'review the PR at {url}'"
118
+ }
119
+ }
120
+ ```
121
+
122
+ ### Use gh CLI to checkout
123
+
124
+ ```json
125
+ {
126
+ "actions": {
127
+ "checkout": "gh pr checkout {number} --repo {owner}/{repo}"
128
+ }
129
+ }
130
+ ```
131
+
132
+ Then `prq run checkout 482`.
87
133
 
88
- Run a custom action defined in your config.
134
+ ### Just open in browser (default)
135
+
136
+ With no config, `prq review` opens the files changed tab and `prq open` opens the PR page. Zero setup needed.
137
+
138
+ ### Template variables
139
+
140
+ | Variable | Example |
141
+ |----------|---------|
142
+ | `{url}` | `https://github.com/org/repo/pull/482` |
143
+ | `{number}` | `482` |
144
+ | `{owner}` | `org` |
145
+ | `{repo}` | `repo` |
146
+ | `{title}` | `fix: handle edge case` |
147
+ | `{author}` | `alice` |
148
+ | `{days}` | `5` |
149
+
150
+ ## Agent & Automation
151
+
152
+ PRQ is fully scriptable with `--json` output and `--yes` flags:
89
153
 
90
154
  ```bash
91
- prq run checkout 482
155
+ # Agent reads the queue
156
+ prq status --json
157
+
158
+ # Agent nudges all stale PRs
159
+ prq status --json | jq -r '.prs[] | select(.category == "stale") | .number' \
160
+ | xargs -I{} prq nudge {} --yes
161
+
162
+ # Claude Code cron
163
+ prq status --json | claude -p "Review needs-re-review PRs older than 7 days"
92
164
  ```
93
165
 
94
- ### `prq init`
166
+ ### Claude Code Skill
167
+
168
+ Install the `/prq` skill to use PRQ inside Claude Code sessions:
169
+
170
+ ```bash
171
+ prq skill --global
172
+ ```
173
+
174
+ Then in Claude Code:
175
+
176
+ ```
177
+ /prq → show queue, ask what to do
178
+ "review 2439" → dispatches to your configured review action
179
+ "nudge all stale PRs" → batch nudge
180
+ ```
95
181
 
96
- Creates a `.prqrc.json` config file in the current directory.
182
+ 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
183
 
98
184
  ## Configuration
99
185
 
@@ -103,7 +189,7 @@ Config is loaded in this order (later overrides earlier):
103
189
  2. `.prqrc.json` — per-project config
104
190
  3. CLI flags
105
191
 
106
- Example `.prqrc.json`:
192
+ Full example:
107
193
 
108
194
  ```json
109
195
  {
@@ -111,25 +197,12 @@ Example `.prqrc.json`:
111
197
  "staleDays": 5,
112
198
  "actions": {
113
199
  "review": "claude -p '/review {url}'",
114
- "checkout": "gh pr checkout {number} --repo {owner}/{repo}"
200
+ "checkout": "gh pr checkout {number} --repo {owner}/{repo}",
201
+ "approve": "gh pr review {number} --repo {owner}/{repo} --approve"
115
202
  }
116
203
  }
117
204
  ```
118
205
 
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
206
  ## License
134
207
 
135
208
  MIT
package/dist/bin/prq.js CHANGED
@@ -6478,6 +6478,122 @@ Available actions: ${available}`);
6478
6478
  await executeCommand(command);
6479
6479
  }
6480
6480
 
6481
+ // src/commands/skill.ts
6482
+ var SKILL_CONTENT = `---
6483
+ name: prq
6484
+ description: PR review queue manager. Use when the user wants to check their PR review queue, review PRs, nudge stale PRs, or manage code review workflow. Triggers on mentions of "review queue", "PRs waiting", "stale PRs", "what needs review", or "prq".
6485
+ ---
6486
+
6487
+ # PRQ — PR Review Queue
6488
+
6489
+ You have access to the \`prq\` CLI tool installed on this machine. Use it to help the user manage their code review queue.
6490
+
6491
+ ## Step 1: Get the queue
6492
+
6493
+ Run this command to get the user's current review queue:
6494
+
6495
+ \`\`\`bash
6496
+ prq status --json
6497
+ \`\`\`
6498
+
6499
+ This returns a JSON object with categorized PRs:
6500
+ - **needs-re-review** — PRs where the user left a review but new commits were pushed after
6501
+ - **requested** — PRs where the user is a requested reviewer
6502
+ - **stale** — PRs with no activity for N days
6503
+ - **waiting-on-others** — PRs the user authored that are waiting on someone else
6504
+
6505
+ ## Step 2: Present the queue
6506
+
6507
+ Show the results in a clear, scannable format grouped by category. For each PR, show:
6508
+ - The category symbol (◆ needs re-review, ● requested, ○ stale, ◇ waiting)
6509
+ - The repo and PR number
6510
+ - The title
6511
+ - The detail (e.g., "new commits since your review 2d ago")
6512
+
6513
+ Then ask what the user wants to do.
6514
+
6515
+ ## Step 3: Act on PRs
6516
+
6517
+ When the user asks to act on a PR, check the \`.prqrc.json\` file in the current directory (or \`~/.config/prq/config.json\`) for custom actions:
6518
+
6519
+ \`\`\`json
6520
+ {
6521
+ "actions": {
6522
+ "review": "/review {url}",
6523
+ "nudge": "shell:prq nudge {number} --yes"
6524
+ }
6525
+ }
6526
+ \`\`\`
6527
+
6528
+ ### Action resolution
6529
+
6530
+ For each action template:
6531
+ - **Starts with \`/\`** — it's a Claude Code skill. Invoke it by running the skill with the interpolated value. For example, \`/review https://github.com/org/repo/pull/123\`
6532
+ - **Starts with \`shell:\`** — it's a shell command. Run it with the Bash tool. For example, \`prq nudge 123 --yes\`
6533
+ - **Otherwise** — treat it as a prompt. Send it as a message.
6534
+
6535
+ ### Template variables
6536
+
6537
+ Replace these in the action template:
6538
+ - \`{url}\` — full PR URL
6539
+ - \`{number}\` — PR number
6540
+ - \`{owner}\` — repo owner
6541
+ - \`{repo}\` — repo name
6542
+ - \`{title}\` — PR title
6543
+ - \`{author}\` — PR author
6544
+
6545
+ ### Default actions (if no config found)
6546
+
6547
+ If no actions are configured, use these defaults:
6548
+ - **review** — invoke \`/review {url}\` if the /review skill exists, otherwise run \`prq review {number}\` to open files changed in browser
6549
+ - **nudge** — run \`prq nudge {number} --yes\`
6550
+ - **open** — run \`prq open {number}\`
6551
+
6552
+ ## Step 4: Batch operations
6553
+
6554
+ If the user says things like "review all needs-re-review PRs" or "nudge all stale PRs":
6555
+
6556
+ 1. Filter the queue JSON by the requested category
6557
+ 2. Confirm the list with the user: "I'll review these 3 PRs: #2439, #2380, #2352. Proceed?"
6558
+ 3. Execute the action on each PR sequentially
6559
+
6560
+ ## Examples
6561
+
6562
+ **User:** "check my review queue"
6563
+ → Run \`prq status --json\`, present results, ask what to do
6564
+
6565
+ **User:** "review 2439"
6566
+ → Look up action for "review", interpolate with PR data, execute
6567
+
6568
+ **User:** "nudge all stale PRs"
6569
+ → Filter stale PRs from queue, confirm, run nudge on each
6570
+
6571
+ **User:** "what PRs are waiting on me?"
6572
+ → Run \`prq status --json\`, show only needs-re-review and requested categories
6573
+
6574
+ **User:** "/prq" with no context
6575
+ → Run \`prq status --json\`, present full queue, ask what to do
6576
+ `;
6577
+ function skillCommand(global) {
6578
+ if (global) {
6579
+ const fs2 = __require("node:fs");
6580
+ const path2 = __require("node:path");
6581
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
6582
+ const skillDir = path2.join(home, ".claude", "skills", "prq");
6583
+ const skillPath = path2.join(skillDir, "SKILL.md");
6584
+ fs2.mkdirSync(skillDir, { recursive: true });
6585
+ fs2.writeFileSync(skillPath, SKILL_CONTENT);
6586
+ console.log(`Installed to ${skillPath}`);
6587
+ } else {
6588
+ const fs2 = __require("node:fs");
6589
+ const skillDir = ".claude/skills/prq";
6590
+ const skillPath = `${skillDir}/SKILL.md`;
6591
+ fs2.mkdirSync(skillDir, { recursive: true });
6592
+ fs2.writeFileSync(skillPath, SKILL_CONTENT);
6593
+ console.log(`Installed to ${skillPath}`);
6594
+ }
6595
+ }
6596
+
6481
6597
  // src/categorize.ts
6482
6598
  function timeAgo(dateStr) {
6483
6599
  const now = Date.now();
@@ -6616,7 +6732,8 @@ function toResolvedPR(pr) {
6616
6732
  updatedAt: pr.updatedAt
6617
6733
  };
6618
6734
  }
6619
- function render(result, selectedIndex, message) {
6735
+ function render(state) {
6736
+ const { result, selectedIndex, message, actionMenu } = state;
6620
6737
  process.stdout.write("\x1B[2J\x1B[H");
6621
6738
  const lines = [];
6622
6739
  lines.push(source_default.bold(` PRQ Status for ${result.user}`));
@@ -6659,8 +6776,20 @@ function render(result, selectedIndex, message) {
6659
6776
  }
6660
6777
  lines.push("");
6661
6778
  lines.push(source_default.dim(` ${"─".repeat(50)}`));
6662
- lines.push("");
6663
- 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("q")} quit`);
6779
+ if (actionMenu) {
6780
+ const pr = result.prs[selectedIndex];
6781
+ lines.push("");
6782
+ lines.push(` ${source_default.bold("Actions")} for ${source_default.white(`#${pr.number}`)}`);
6783
+ lines.push("");
6784
+ for (let i = 0;i < actionMenu.length; i++) {
6785
+ lines.push(` ${source_default.white(String(i + 1))}. ${actionMenu[i].name}`);
6786
+ }
6787
+ lines.push("");
6788
+ lines.push(` ${source_default.dim("1-9")} run action ${source_default.white("q")} back`);
6789
+ } else {
6790
+ lines.push("");
6791
+ 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`);
6792
+ }
6664
6793
  if (message) {
6665
6794
  lines.push("");
6666
6795
  lines.push(` ${message}`);
@@ -6668,6 +6797,17 @@ function render(result, selectedIndex, message) {
6668
6797
  process.stdout.write(lines.join(`
6669
6798
  `));
6670
6799
  }
6800
+ async function runAction(actionName, template, pr, state) {
6801
+ const cmd = interpolate(template, buildContext(toResolvedPR(pr)));
6802
+ state.message = source_default.dim(`running ${actionName} on ${pr.repo}#${pr.number}...`);
6803
+ render(state);
6804
+ try {
6805
+ await executeCommand(cmd);
6806
+ return source_default.green(`${actionName}: ${pr.repo}#${pr.number}`);
6807
+ } catch {
6808
+ return source_default.red(`${actionName} failed`);
6809
+ }
6810
+ }
6671
6811
  async function interactiveMode(result, config) {
6672
6812
  if (result.prs.length === 0) {
6673
6813
  console.log(source_default.green(`
@@ -6675,9 +6815,14 @@ async function interactiveMode(result, config) {
6675
6815
  `));
6676
6816
  return;
6677
6817
  }
6678
- let selectedIndex = 0;
6679
- let message = "";
6680
6818
  const total = result.prs.length;
6819
+ const allActions = listActions(config);
6820
+ const state = {
6821
+ result,
6822
+ selectedIndex: 0,
6823
+ message: "",
6824
+ actionMenu: null
6825
+ };
6681
6826
  if (!process.stdin.isTTY) {
6682
6827
  process.stdout.write(`Interactive mode requires a terminal. Use prq status instead.
6683
6828
  `);
@@ -6687,7 +6832,7 @@ async function interactiveMode(result, config) {
6687
6832
  process.stdin.resume();
6688
6833
  process.stdin.setEncoding("utf8");
6689
6834
  process.stdout.write("\x1B[?25l");
6690
- render(result, selectedIndex, message);
6835
+ render(state);
6691
6836
  return new Promise((resolve) => {
6692
6837
  const cleanup = () => {
6693
6838
  process.stdin.setRawMode(false);
@@ -6696,7 +6841,26 @@ async function interactiveMode(result, config) {
6696
6841
  process.stdout.write("\x1B[?25h\x1B[2J\x1B[H");
6697
6842
  };
6698
6843
  process.stdin.on("data", async (key) => {
6699
- const pr = result.prs[selectedIndex];
6844
+ const pr = result.prs[state.selectedIndex];
6845
+ if (state.actionMenu) {
6846
+ if (key === "q" || key === "\x1B" || key === "a") {
6847
+ state.actionMenu = null;
6848
+ state.message = "";
6849
+ } else if (key === "\x03") {
6850
+ cleanup();
6851
+ resolve();
6852
+ return;
6853
+ } else {
6854
+ const idx = parseInt(key, 10);
6855
+ if (idx >= 1 && idx <= state.actionMenu.length) {
6856
+ const action = state.actionMenu[idx - 1];
6857
+ state.message = await runAction(action.name, action.template, pr, state);
6858
+ state.actionMenu = null;
6859
+ }
6860
+ }
6861
+ render(state);
6862
+ return;
6863
+ }
6700
6864
  switch (key) {
6701
6865
  case "q":
6702
6866
  case "\x03":
@@ -6704,55 +6868,31 @@ async function interactiveMode(result, config) {
6704
6868
  resolve();
6705
6869
  return;
6706
6870
  case "\x1B[A":
6707
- selectedIndex = Math.max(0, selectedIndex - 1);
6708
- message = "";
6871
+ state.selectedIndex = Math.max(0, state.selectedIndex - 1);
6872
+ state.message = "";
6709
6873
  break;
6710
6874
  case "\x1B[B":
6711
- selectedIndex = Math.min(total - 1, selectedIndex + 1);
6712
- message = "";
6875
+ state.selectedIndex = Math.min(total - 1, state.selectedIndex + 1);
6876
+ state.message = "";
6713
6877
  break;
6714
6878
  case "o": {
6715
- const template = getAction("open", config);
6879
+ const template = allActions.open;
6716
6880
  if (template) {
6717
- const cmd = interpolate(template, buildContext(toResolvedPR(pr)));
6718
- message = source_default.dim(`opening ${pr.repo}#${pr.number}...`);
6719
- render(result, selectedIndex, message);
6720
- try {
6721
- await executeCommand(cmd);
6722
- message = source_default.green(`opened ${pr.repo}#${pr.number}`);
6723
- } catch {
6724
- message = source_default.red("failed to open");
6725
- }
6881
+ state.message = await runAction("open", template, pr, state);
6726
6882
  }
6727
6883
  break;
6728
6884
  }
6729
6885
  case "r": {
6730
- const template = getAction("review", config);
6886
+ const template = allActions.review;
6731
6887
  if (template) {
6732
- const cmd = interpolate(template, buildContext(toResolvedPR(pr)));
6733
- message = source_default.dim(`opening review for ${pr.repo}#${pr.number}...`);
6734
- render(result, selectedIndex, message);
6735
- try {
6736
- await executeCommand(cmd);
6737
- message = source_default.green(`opened review for ${pr.repo}#${pr.number}`);
6738
- } catch {
6739
- message = source_default.red("failed to open review");
6740
- }
6888
+ state.message = await runAction("review", template, pr, state);
6741
6889
  }
6742
6890
  break;
6743
6891
  }
6744
6892
  case "n": {
6745
- const template = getAction("nudge", config);
6893
+ const template = allActions.nudge;
6746
6894
  if (template) {
6747
- const cmd = interpolate(template, buildContext(toResolvedPR(pr)));
6748
- message = source_default.dim(`nudging ${pr.repo}#${pr.number}...`);
6749
- render(result, selectedIndex, message);
6750
- try {
6751
- await executeCommand(cmd);
6752
- message = source_default.green(`nudged ${pr.repo}#${pr.number}`);
6753
- } catch {
6754
- message = source_default.red("failed to nudge");
6755
- }
6895
+ state.message = await runAction("nudge", template, pr, state);
6756
6896
  }
6757
6897
  break;
6758
6898
  }
@@ -6761,16 +6901,25 @@ async function interactiveMode(result, config) {
6761
6901
  try {
6762
6902
  const proc = process.platform === "darwin" ? "pbcopy" : process.platform === "linux" ? "xclip -selection clipboard" : "clip";
6763
6903
  await executeCommand(`echo "${url}" | ${proc}`);
6764
- message = source_default.green("url copied");
6904
+ state.message = source_default.green("url copied");
6765
6905
  } catch {
6766
- message = source_default.dim(url);
6906
+ state.message = source_default.dim(url);
6767
6907
  }
6768
6908
  break;
6769
6909
  }
6910
+ case "a": {
6911
+ const entries = Object.entries(allActions);
6912
+ state.actionMenu = entries.map(([name, template]) => ({
6913
+ name,
6914
+ template
6915
+ }));
6916
+ state.message = "";
6917
+ break;
6918
+ }
6770
6919
  default:
6771
6920
  break;
6772
6921
  }
6773
- render(result, selectedIndex, message);
6922
+ render(state);
6774
6923
  });
6775
6924
  });
6776
6925
  }
@@ -10893,12 +11042,12 @@ function getVersion() {
10893
11042
  function createCLI() {
10894
11043
  const program2 = new Command;
10895
11044
  program2.name("prq").description("PR Queue — see what code reviews need your attention").version(getVersion());
10896
- 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("-i, --interactive", "Interactive mode with keyboard shortcuts").action(async (opts) => {
11045
+ 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) => {
10897
11046
  const config = loadConfig({
10898
11047
  repos: opts.repos,
10899
11048
  staleDays: opts.staleDays ? parseInt(opts.staleDays, 10) : undefined
10900
11049
  });
10901
- await statusCommand(config, opts.json ?? false, opts.interactive ?? false);
11050
+ await statusCommand(config, opts.json ?? false, opts.interactive ?? true);
10902
11051
  });
10903
11052
  program2.command("open <identifier>").description("Open a PR in the browser").action(async (identifier) => {
10904
11053
  const config = loadConfig({});
@@ -10919,6 +11068,9 @@ function createCLI() {
10919
11068
  const config = loadConfig({});
10920
11069
  await runCommand(action, identifier, config);
10921
11070
  });
11071
+ program2.command("skill").description("Install the /prq skill for Claude Code").option("-g, --global", "Install globally (~/.claude/skills/prq/)").action((opts) => {
11072
+ skillCommand(opts.global ?? false);
11073
+ });
10922
11074
  program2.command("init").description("Create config file interactively").action(async () => {
10923
11075
  await initCommand();
10924
11076
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prq-cli",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "PR Queue — see what code reviews need your attention",
5
5
  "type": "module",
6
6
  "bin": {