@quickchatai/pi-quickreview 1.1.0 → 1.3.1

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 (241) hide show
  1. package/README.md +79 -27
  2. package/assets/config.example.toml +60 -14
  3. package/assets/prompts/onboarding.md +58 -18
  4. package/assets/schemas/review-result.v1.json +60 -0
  5. package/dist/extensions/quickreview.d.ts +13 -5
  6. package/dist/extensions/quickreview.d.ts.map +1 -1
  7. package/dist/extensions/quickreview.js +77 -25
  8. package/dist/extensions/quickreview.js.map +1 -1
  9. package/dist/src/engine/auth.d.ts +4 -0
  10. package/dist/src/engine/auth.d.ts.map +1 -1
  11. package/dist/src/engine/auth.js +11 -2
  12. package/dist/src/engine/auth.js.map +1 -1
  13. package/dist/src/engine/envmap.d.ts.map +1 -1
  14. package/dist/src/engine/envmap.js +5 -0
  15. package/dist/src/engine/envmap.js.map +1 -1
  16. package/dist/src/engine/lens/activity.d.ts +45 -0
  17. package/dist/src/engine/lens/activity.d.ts.map +1 -0
  18. package/dist/src/engine/lens/activity.js +118 -0
  19. package/dist/src/engine/lens/activity.js.map +1 -0
  20. package/dist/src/engine/lens/runlens.d.ts +7 -0
  21. package/dist/src/engine/lens/runlens.d.ts.map +1 -1
  22. package/dist/src/engine/lens/runlens.js +30 -1
  23. package/dist/src/engine/lens/runlens.js.map +1 -1
  24. package/dist/src/engine/lens/tool.d.ts +7 -0
  25. package/dist/src/engine/lens/tool.d.ts.map +1 -1
  26. package/dist/src/engine/lens/tool.js +101 -18
  27. package/dist/src/engine/lens/tool.js.map +1 -1
  28. package/dist/src/engine/lens/wave.d.ts +6 -0
  29. package/dist/src/engine/lens/wave.d.ts.map +1 -1
  30. package/dist/src/engine/lens/wave.js +16 -0
  31. package/dist/src/engine/lens/wave.js.map +1 -1
  32. package/dist/src/engine/pisdk.d.ts +9 -0
  33. package/dist/src/engine/pisdk.d.ts.map +1 -1
  34. package/dist/src/engine/pisdk.js +29 -4
  35. package/dist/src/engine/pisdk.js.map +1 -1
  36. package/dist/src/githubAuth.d.ts +39 -1
  37. package/dist/src/githubAuth.d.ts.map +1 -1
  38. package/dist/src/githubAuth.js +75 -8
  39. package/dist/src/githubAuth.js.map +1 -1
  40. package/dist/src/guards.d.ts +14 -1
  41. package/dist/src/guards.d.ts.map +1 -1
  42. package/dist/src/guards.js +61 -2
  43. package/dist/src/guards.js.map +1 -1
  44. package/dist/src/homes.js +1 -1
  45. package/dist/src/homes.js.map +1 -1
  46. package/dist/src/identity.d.ts +34 -0
  47. package/dist/src/identity.d.ts.map +1 -0
  48. package/dist/src/identity.js +67 -0
  49. package/dist/src/identity.js.map +1 -0
  50. package/dist/src/live/events.d.ts +3 -0
  51. package/dist/src/live/events.d.ts.map +1 -1
  52. package/dist/src/live/events.js.map +1 -1
  53. package/dist/src/live/lensline.d.ts +20 -0
  54. package/dist/src/live/lensline.d.ts.map +1 -0
  55. package/dist/src/live/lensline.js +70 -0
  56. package/dist/src/live/lensline.js.map +1 -0
  57. package/dist/src/live/projection.d.ts +55 -0
  58. package/dist/src/live/projection.d.ts.map +1 -0
  59. package/dist/src/live/projection.js +465 -0
  60. package/dist/src/live/projection.js.map +1 -0
  61. package/dist/src/live/read.d.ts +24 -0
  62. package/dist/src/live/read.d.ts.map +1 -0
  63. package/dist/src/live/read.js +60 -0
  64. package/dist/src/live/read.js.map +1 -0
  65. package/dist/src/live/writer.d.ts +3 -0
  66. package/dist/src/live/writer.d.ts.map +1 -1
  67. package/dist/src/live/writer.js +6 -1
  68. package/dist/src/live/writer.js.map +1 -1
  69. package/dist/src/localreview.d.ts +18 -8
  70. package/dist/src/localreview.d.ts.map +1 -1
  71. package/dist/src/localreview.js +103 -43
  72. package/dist/src/localreview.js.map +1 -1
  73. package/dist/src/modelroute.d.ts +42 -0
  74. package/dist/src/modelroute.d.ts.map +1 -0
  75. package/dist/src/modelroute.js +126 -0
  76. package/dist/src/modelroute.js.map +1 -0
  77. package/dist/src/plugin/args.d.ts +38 -7
  78. package/dist/src/plugin/args.d.ts.map +1 -1
  79. package/dist/src/plugin/args.js +134 -37
  80. package/dist/src/plugin/args.js.map +1 -1
  81. package/dist/src/plugin/login.d.ts +11 -4
  82. package/dist/src/plugin/login.d.ts.map +1 -1
  83. package/dist/src/plugin/login.js +28 -26
  84. package/dist/src/plugin/login.js.map +1 -1
  85. package/dist/src/plugin/messages.d.ts +7 -0
  86. package/dist/src/plugin/messages.d.ts.map +1 -0
  87. package/dist/src/plugin/messages.js +13 -0
  88. package/dist/src/plugin/messages.js.map +1 -0
  89. package/dist/src/plugin/review.d.ts +52 -6
  90. package/dist/src/plugin/review.d.ts.map +1 -1
  91. package/dist/src/plugin/review.js +269 -99
  92. package/dist/src/plugin/review.js.map +1 -1
  93. package/dist/src/plugin/scan.d.ts +80 -44
  94. package/dist/src/plugin/scan.d.ts.map +1 -1
  95. package/dist/src/plugin/scan.js +450 -233
  96. package/dist/src/plugin/scan.js.map +1 -1
  97. package/dist/src/plugin/scancases.d.ts +33 -0
  98. package/dist/src/plugin/scancases.d.ts.map +1 -0
  99. package/dist/src/plugin/scancases.js +153 -0
  100. package/dist/src/plugin/scancases.js.map +1 -0
  101. package/dist/src/plugin/settings.d.ts +18 -0
  102. package/dist/src/plugin/settings.d.ts.map +1 -0
  103. package/dist/src/plugin/settings.js +47 -0
  104. package/dist/src/plugin/settings.js.map +1 -0
  105. package/dist/src/plugin/setup.d.ts +35 -12
  106. package/dist/src/plugin/setup.d.ts.map +1 -1
  107. package/dist/src/plugin/setup.js +258 -118
  108. package/dist/src/plugin/setup.js.map +1 -1
  109. package/dist/src/plugin/versiongate.js +1 -1
  110. package/dist/src/plugin/versiongate.js.map +1 -1
  111. package/dist/src/profileoverrides.d.ts +3 -0
  112. package/dist/src/profileoverrides.d.ts.map +1 -1
  113. package/dist/src/profileoverrides.js +9 -2
  114. package/dist/src/profileoverrides.js.map +1 -1
  115. package/dist/src/reviewapi.d.ts +22 -31
  116. package/dist/src/reviewapi.d.ts.map +1 -1
  117. package/dist/src/reviewapi.js +90 -66
  118. package/dist/src/reviewapi.js.map +1 -1
  119. package/dist/src/reviewconfig.d.ts +12 -0
  120. package/dist/src/reviewconfig.d.ts.map +1 -1
  121. package/dist/src/reviewconfig.js +9 -1
  122. package/dist/src/reviewconfig.js.map +1 -1
  123. package/dist/src/reviewdest.d.ts +1 -1
  124. package/dist/src/reviewdest.d.ts.map +1 -1
  125. package/dist/src/reviewdest.js +4 -3
  126. package/dist/src/reviewdest.js.map +1 -1
  127. package/dist/src/reviewtarget.d.ts +36 -0
  128. package/dist/src/reviewtarget.d.ts.map +1 -0
  129. package/dist/src/reviewtarget.js +6 -0
  130. package/dist/src/reviewtarget.js.map +1 -0
  131. package/dist/src/round-progress.d.ts +5 -0
  132. package/dist/src/round-progress.d.ts.map +1 -1
  133. package/dist/src/round-progress.js.map +1 -1
  134. package/dist/src/savedpost.d.ts +65 -0
  135. package/dist/src/savedpost.d.ts.map +1 -0
  136. package/dist/src/savedpost.js +131 -0
  137. package/dist/src/savedpost.js.map +1 -0
  138. package/dist/src/scan/caseread.d.ts +84 -0
  139. package/dist/src/scan/caseread.d.ts.map +1 -0
  140. package/dist/src/scan/caseread.js +263 -0
  141. package/dist/src/scan/caseread.js.map +1 -0
  142. package/dist/src/scan/channelfs.d.ts +6 -0
  143. package/dist/src/scan/channelfs.d.ts.map +1 -0
  144. package/dist/src/scan/channelfs.js +27 -0
  145. package/dist/src/scan/channelfs.js.map +1 -0
  146. package/dist/src/scan/cutrender.d.ts +13 -0
  147. package/dist/src/scan/cutrender.d.ts.map +1 -0
  148. package/dist/src/scan/cutrender.js +51 -0
  149. package/dist/src/scan/cutrender.js.map +1 -0
  150. package/dist/src/scan/facts.d.ts +72 -0
  151. package/dist/src/scan/facts.d.ts.map +1 -0
  152. package/dist/src/scan/facts.js +593 -0
  153. package/dist/src/scan/facts.js.map +1 -0
  154. package/dist/src/scan/findings.d.ts +320 -0
  155. package/dist/src/scan/findings.d.ts.map +1 -0
  156. package/dist/src/scan/findings.js +948 -0
  157. package/dist/src/scan/findings.js.map +1 -0
  158. package/dist/src/scan/ledger.d.ts +116 -0
  159. package/dist/src/scan/ledger.d.ts.map +1 -0
  160. package/dist/src/scan/ledger.js +207 -0
  161. package/dist/src/scan/ledger.js.map +1 -0
  162. package/dist/src/scan/presentation.d.ts +19 -0
  163. package/dist/src/scan/presentation.d.ts.map +1 -0
  164. package/dist/src/scan/presentation.js +9 -0
  165. package/dist/src/scan/presentation.js.map +1 -0
  166. package/dist/src/scan/scan.d.ts +354 -0
  167. package/dist/src/scan/scan.d.ts.map +1 -0
  168. package/dist/src/scan/scan.js +725 -0
  169. package/dist/src/scan/scan.js.map +1 -0
  170. package/dist/src/scan/scanagents.d.ts +23 -0
  171. package/dist/src/scan/scanagents.d.ts.map +1 -0
  172. package/dist/src/scan/scanagents.js +99 -0
  173. package/dist/src/scan/scanagents.js.map +1 -0
  174. package/dist/src/scan/scanassemble.d.ts +65 -0
  175. package/dist/src/scan/scanassemble.d.ts.map +1 -0
  176. package/dist/src/scan/scanassemble.js +93 -0
  177. package/dist/src/scan/scanassemble.js.map +1 -0
  178. package/dist/src/scan/scanfs.d.ts +26 -0
  179. package/dist/src/scan/scanfs.d.ts.map +1 -0
  180. package/dist/src/scan/scanfs.js +229 -0
  181. package/dist/src/scan/scanfs.js.map +1 -0
  182. package/dist/src/scan/scanlease.d.ts +50 -0
  183. package/dist/src/scan/scanlease.d.ts.map +1 -0
  184. package/dist/src/scan/scanlease.js +251 -0
  185. package/dist/src/scan/scanlease.js.map +1 -0
  186. package/dist/src/scan/scanleaves.d.ts +55 -0
  187. package/dist/src/scan/scanleaves.d.ts.map +1 -0
  188. package/dist/src/scan/scanleaves.js +258 -0
  189. package/dist/src/scan/scanleaves.js.map +1 -0
  190. package/dist/src/scan/scanports.d.ts +79 -0
  191. package/dist/src/scan/scanports.d.ts.map +1 -0
  192. package/dist/src/scan/scanports.js +8 -0
  193. package/dist/src/scan/scanports.js.map +1 -0
  194. package/dist/src/scan/scanrender.d.ts +128 -0
  195. package/dist/src/scan/scanrender.d.ts.map +1 -0
  196. package/dist/src/scan/scanrender.js +527 -0
  197. package/dist/src/scan/scanrender.js.map +1 -0
  198. package/dist/src/scan/scanreport.d.ts +126 -0
  199. package/dist/src/scan/scanreport.d.ts.map +1 -0
  200. package/dist/src/scan/scanreport.js +289 -0
  201. package/dist/src/scan/scanreport.js.map +1 -0
  202. package/dist/src/scan/scanrun.d.ts +472 -0
  203. package/dist/src/scan/scanrun.d.ts.map +1 -0
  204. package/dist/src/scan/scanrun.js +1733 -0
  205. package/dist/src/scan/scanrun.js.map +1 -0
  206. package/dist/src/scan/scantree.d.ts +21 -0
  207. package/dist/src/scan/scantree.d.ts.map +1 -0
  208. package/dist/src/scan/scantree.js +297 -0
  209. package/dist/src/scan/scantree.js.map +1 -0
  210. package/dist/src/scan/scanverbs.d.ts +208 -0
  211. package/dist/src/scan/scanverbs.d.ts.map +1 -0
  212. package/dist/src/scan/scanverbs.js +689 -0
  213. package/dist/src/scan/scanverbs.js.map +1 -0
  214. package/dist/src/scan/stage2.d.ts +221 -0
  215. package/dist/src/scan/stage2.d.ts.map +1 -0
  216. package/dist/src/scan/stage2.js +617 -0
  217. package/dist/src/scan/stage2.js.map +1 -0
  218. package/dist/src/scan/stage2request.d.ts +125 -0
  219. package/dist/src/scan/stage2request.d.ts.map +1 -0
  220. package/dist/src/scan/stage2request.js +259 -0
  221. package/dist/src/scan/stage2request.js.map +1 -0
  222. package/dist/src/scan/textsniff.d.ts +14 -0
  223. package/dist/src/scan/textsniff.d.ts.map +1 -0
  224. package/dist/src/scan/textsniff.js +88 -0
  225. package/dist/src/scan/textsniff.js.map +1 -0
  226. package/dist/src/scan/unitcut.d.ts +135 -0
  227. package/dist/src/scan/unitcut.d.ts.map +1 -0
  228. package/dist/src/scan/unitcut.js +437 -0
  229. package/dist/src/scan/unitcut.js.map +1 -0
  230. package/dist/src/scan/unitcutstore.d.ts +155 -0
  231. package/dist/src/scan/unitcutstore.d.ts.map +1 -0
  232. package/dist/src/scan/unitcutstore.js +381 -0
  233. package/dist/src/scan/unitcutstore.js.map +1 -0
  234. package/dist/src/setupchecklist.d.ts +240 -0
  235. package/dist/src/setupchecklist.d.ts.map +1 -0
  236. package/dist/src/setupchecklist.js +407 -0
  237. package/dist/src/setupchecklist.js.map +1 -0
  238. package/package.json +7 -3
  239. package/skills/qcr-review/SKILL.md +24 -0
  240. package/skills/qcr-scan/SKILL.md +23 -0
  241. package/skills/qcr-setup/SKILL.md +18 -0
package/README.md CHANGED
@@ -9,21 +9,67 @@ pi install npm:@quickchatai/pi-quickreview
9
9
 
10
10
  ## Commands
11
11
 
12
- - `/review` reviews the current branch against its base. `/review 123` (or a
13
- pull request URL) reviews a PR, and `/review --uncommitted` the uncommitted
14
- tree. `--preview` shows the plan and the price without running anything.
15
- The result is shown in the session, saved as markdown and JSON, or posted
16
- to the PR as a comment-only review (`--to pr`); pi asks each time, unless
17
- you keep an answer as the repo's default.
18
- - `/scan` scans the whole repo for defects, priced first and started only on
19
- your yes. It runs the `qcr` CLI on your machine; `--sandbox docker` runs it
20
- in the scan sandbox instead.
21
- - `/selfimprove` scans the repo, then hands the findings to this session's
22
- agent with a fix loop: triage, fix with tests, review, and a re-scan of
23
- what changed.
24
- - `/qcr-setup` checks the pi version, the login, git, GitHub access for PR
25
- targets and the `qcr` CLI, and offers to install `qcr`
26
- (`npm i -g @quickchatai/quickreview`).
12
+ Each command is also a skill of the same name, so the model in your session
13
+ knows the command and can tell you the line to type.
14
+
15
+ - `/qcr-review [preset] [target]` reviews in the background: the command
16
+ returns at once, you keep chatting, the status line shows the review's
17
+ progress, and the result arrives in the session as a message (and is kept
18
+ as markdown and JSON under the qcr state home).
19
+ - The target: nothing reviews the current branch against its base together
20
+ with its uncommitted changes, as one review; `123`, `#123` or a pull
21
+ request URL reviews a PR; a branch name reviews that branch;
22
+ `--uncommitted` reviews the uncommitted changes alone.
23
+ - The preset, first when given: `quick` (lower reasoning, about half the
24
+ cost), `full` (the whole target again at the highest reasoning) or
25
+ `security` (only the security and data-safety lenses the change
26
+ triggers).
27
+ - `--preview` shows the plan and the price without running anything;
28
+ `--stop` stops the review that is running. One review runs per session
29
+ at a time, and ending the session stops it.
30
+ - After a PR review, your posting rule decides whether it goes to the PR
31
+ as a comment-only review (see Settings).
32
+ - `/qcr-scan [--delta] [--sha REF] [--preview]` scans the whole repo for
33
+ defects, priced first and started only on your yes. It runs in the
34
+ background in this pi, like a review: a status line while it runs, the new
35
+ findings as a message when it ends, `/qcr-scan stop` to stop it. Its cases
36
+ are SDK sessions of this pi behind the same read-only bash guard as the
37
+ review's lenses. `/qcr-scan findings`, `status`, `units` and the other
38
+ scan subcommands pass through as typed. The scan sandbox (a container) and
39
+ dismissing a finding are the `qcr` app's (`qcr scan`).
40
+ - `/qcr-setup` checks the pi version, the login, git and GitHub access for
41
+ PR targets. It then offers to set up this repo's profile (`.qcr/`), No
42
+ first: on your yes, your agent in the session surveys the repo, reads its
43
+ review history, interviews you and writes the profile for you to commit.
44
+ `/qcr-setup profile` starts that straight away. Its checks are steps on a
45
+ setup checklist (`src/setupchecklist.ts`) that the `qcr` app extends with
46
+ its own steps.
47
+
48
+ `/review`, `/scan` and `/selfimprove` are gone: pi's command namespace is
49
+ shared with every other extension, so the commands carry the `qcr-` prefix.
50
+ `/review` is `/qcr-review`, `/scan` is `/qcr-scan`, and `/selfimprove` is a
51
+ command of the `qcr` app's own pi (`qcr pi`).
52
+
53
+ ## Settings
54
+
55
+ Your own defaults live in pi's settings (`~/.pi/agent/settings.json`, or the
56
+ project's `.pi/settings.json`), under `quickreview`:
57
+
58
+ ```json
59
+ {
60
+ "quickreview": {
61
+ "posting": "ask",
62
+ "preset": "quick"
63
+ }
64
+ }
65
+ ```
66
+
67
+ - `posting` decides what happens after a PR review: `ask` (the default)
68
+ asks, with "No, keep it here" offered first; `never` keeps every review in
69
+ the session; `always` posts without asking.
70
+ - `preset` is the preset a `/qcr-review` without one runs under.
71
+
72
+ Rules for one repository live in its profile, not here.
27
73
 
28
74
  ## Which pi
29
75
 
@@ -42,32 +88,38 @@ exactly instead; `qcr pi` starts that pinned pi with this plugin preloaded.
42
88
  - A pi login for the review's models (`/login` in pi). The review borrows
43
89
  it: pi refreshes it when needed, and the review only ever reads a copy.
44
90
  An API key for another provider is not used in its place: with no login
45
- for the review's provider, `/review` stops and names `/login`.
91
+ for the review's provider, `/qcr-review` stops and names `/login`. The
92
+ scan borrows it the same way.
46
93
  - For a PR: the App when a qcr install configures one, else `GITHUB_TOKEN`,
47
94
  `GH_TOKEN` or `gh auth login`, in that order.
48
- - For posting (`--to pr`): a qcr config with `dry_run = false`. The shipped
49
- defaults keep `dry_run` on, and then `/review` refuses to post and says so.
95
+ - For posting: a qcr config with `dry_run = false`. The shipped defaults keep
96
+ `dry_run` on, and then a post is recorded under the qcr state home
97
+ (`review/dryrun/`) and nothing is sent; the post question says so.
50
98
 
51
99
  ## What it never does
52
100
 
53
- - The review never writes to your checkout: it reads the tree as it is.
54
- (`/selfimprove`'s fixes are made by your own session's agent, under your
55
- pi's own tools and permissions, not by the review.)
56
- - The review never runs your code, tests or app: it reads code and CI.
57
- - It never posts unless you choose `--to pr`, and then it posts one
58
- comment-only review through the same mutation gate the bot uses. It never
59
- approves, requests changes or dismisses a review.
101
+ - The review and the scan never write to your checkout: they read the tree
102
+ as it is.
103
+ - The review and the scan never run your code, tests or app: they read code
104
+ (and the review, CI).
105
+ - It never runs the `qcr` CLI.
106
+ - It never posts unless you say yes to the post question (or your posting
107
+ rule is `always`), and then it posts one comment-only review through the
108
+ same mutation gate the bot uses. It never approves, requests changes or
109
+ dismisses a review.
60
110
  - It never refreshes your login itself, and never hands a token to the
61
111
  model's tools.
62
112
  - It never gives your session a tool. The review's lens passes run in their
63
113
  own sessions, with none of your pi extensions, skills or settings, and
64
- your session only sees the result.
114
+ your session only sees the result. The skills it ships are instructions
115
+ for your session's model, naming the commands.
65
116
  - It never sets or flips `dry_run`.
66
117
  - It never starts `claude`.
67
118
 
68
119
  ## What ships in the package
69
120
 
70
- The compiled review core and the plugin (`dist/`), and under `assets/` the
121
+ The compiled review core and the plugin (`dist/`), one skill per command
122
+ (`skills/`), and under `assets/` the
71
123
  data the core reads: the agents, prompts and seeds, the schemas, the
72
124
  profiles and the shipped config defaults. `assets/` is copied from the
73
125
  repository at pack time and checked file by file against its source, so the
@@ -6,10 +6,11 @@
6
6
  # supply are marked "← FILL (n)" — grep for FILL. Flip dry_run to false only
7
7
  # as a deliberate cutover act, never as part of setup.
8
8
  #
9
- # YOU DO NOT HAVE TO FILL THIS BY HAND: `scripts/qcr onboard` interviews you
10
- # for the few values only you can answer, derives the rest, and patches this
11
- # file in place — every comment survives, and a re-run edits only what changed.
12
- # It never writes dry_run in either direction; going live is its own explicit
9
+ # YOU DO NOT HAVE TO FILL THIS BY HAND: a bare `qcr` (the home) writes the
10
+ # repository you choose and its defaults, and the setup wizard's steps
11
+ # interview you for the rest, derive what they can, and patch this file in
12
+ # place — every comment survives, and a re-run edits only what changed.
13
+ # Neither writes dry_run in either direction; going live is its own explicit
13
14
  # step. See docs/onboarding.md.
14
15
  # ONE mutation class is exempt and executes for real even here: the App
15
16
  # re-pointing its OWN webhook URL (see [ingress] below) — it can never touch
@@ -27,8 +28,22 @@ timezone = "UTC" # ← FILL: your IANA timezone, e.g
27
28
 
28
29
  [github]
29
30
  repo = "" # ← FILL (1): the repo to review, "owner/name"
30
- app_slug = "" # ← FILL (2): your GitHub App slug
31
- bot_login = "" # ← FILL (3): the App bot login, "<app_slug>[bot]"
31
+ # Whose GitHub credential the daemon runs on:
32
+ # "app" (the default; a missing key means "app") — a GitHub App: its
33
+ # installation token, webhooks, APPROVE / REQUEST_CHANGES reviews.
34
+ # "user" — your OWN GitHub account, no App. Polling only: [ingress] shape
35
+ # must be "polling" (config load refuses anything else), no webhooks,
36
+ # no webhook self-heal. Every review posts as a COMMENT whose body
37
+ # states the verdict (an automated verdict never counts as your
38
+ # approval, and GitHub refuses either on your own PR). The token is
39
+ # read from the FILE <secrets dir>/github_token (0600, the token
40
+ # alone), which `qcr github-token sync` writes from your `gh` login;
41
+ # never from the environment or a command line. app_slug may be "";
42
+ # bot_login is your own GitHub login. The App secrets (app_id,
43
+ # app.pem, webhook_secret) are not needed.
44
+ #auth = "app"
45
+ app_slug = "" # ← FILL (2): your GitHub App slug ("" under auth = "user")
46
+ bot_login = "" # ← FILL (3): the App bot login, "<app_slug>[bot]" (your login under auth = "user")
32
47
  review_team = "" # ← FILL (4): "org/team" whose review request triggers
33
48
  # There is no reviewer knob here. The reviewer never hands a PR back: it always
34
49
  # decides on the merits and posts a verdict. If you want a named person told
@@ -39,7 +54,8 @@ in_progress_label = "AI review in progress"
39
54
  reviewed_label = "Automatic Review"
40
55
  improvement_label = "Bot improvement"
41
56
  issue_label = "bot-filed"
42
- # secrets dir: app_id, app.pem, webhook_secret, tunnel_token; optional openai_api_key (pi, API-key
57
+ # secrets dir: app_id, app.pem, webhook_secret, tunnel_token (auth = "user": github_token instead
58
+ # of the first three); optional openai_api_key (pi, API-key
43
59
  # route) and openai_embeddings_api_key (only with embedding_provider = "openai" in the openviking table)
44
60
  # "" (recommended) = the install's config home, $XDG_CONFIG_HOME/qcr/<install>/secrets (the old
45
61
  # ~/.config/quickreview-bot is never read — `qcr install migrate` moves it). A path here wins.
@@ -81,8 +97,12 @@ port = 8787 # loopback only; your HTTPS ingress
81
97
  # touches only the App's own configuration, never the reviewed repo. Off by
82
98
  # default: with the section absent (or shape = "none") no watcher ever starts —
83
99
  # a stable hostname (named tunnel, VM route) needs none of this.
100
+ # shape = "polling" takes no webhooks at all: the daemon's /webhook route
101
+ # refuses every delivery, no webhook_secret is read, and the reconcile poll
102
+ # (poll_interval_s, below) is the only trigger. [github] auth = "user"
103
+ # requires it.
84
104
  #[ingress]
85
- #shape = "tunnel-file" # "none" (default) | "tunnel-file"
105
+ #shape = "tunnel-file" # "none" (default) | "tunnel-file" | "polling"
86
106
  #hostname_file = "" # "" ⇒ <root>/state/ingress/hostname
87
107
  #debounce_ms = 3000 # settle time after a file change
88
108
  #sweep_interval_s = 300 # polling backstop behind fs.watch
@@ -204,7 +224,9 @@ improvement_pr_deny_prefixes = ["migrations/", "infra/", "ansible/", ".github/wo
204
224
  [models]
205
225
  # default for every role; tiered pass models below
206
226
  # Provider prefix is `openai-codex/` — the ChatGPT-OAuth route's provider key
207
- # in pi's auth.json (direct `openai/` needs an API key we don't ship).
227
+ # in pi's auth.json. Any OpenAI login serves it: when pi holds no
228
+ # `openai-codex` login but an `openai` one (pi 1.4's Sign in with ChatGPT, or
229
+ # an OpenAI API key), the same model runs on `openai` (docs/llm-setup.md).
208
230
  default = "openai-codex/gpt-6.1-sol"
209
231
  conversation = "openai-codex/gpt-6.1-sol"
210
232
  # Passes always run at sol-high — single variant, not raisable (already top).
@@ -261,7 +283,11 @@ small_diff_lines = 150
261
283
  # memory forward follows this knob too — it reaches the daemon
262
284
  # container's loopback memory engine with a plain `docker exec`
263
285
  # (the forward script's --local mode) instead of the ssh hop.
264
- # Always explicit: an empty ssh_host does NOT mean local.
286
+ # Onboarding writes this from the recorded topology. Until it has (ssh with an
287
+ # EMPTY ssh_host), the TUI never runs `ssh ""`: on a compose project (the
288
+ # checklist recorded the local topology, or the project .env pins
289
+ # QCR_VERSION) it reads the local stack and says so once; otherwise every
290
+ # surface says "ssh_host is empty — set it to the VM's ssh alias".
265
291
  target = "ssh"
266
292
  ssh_host = "" # ← FILL (7): ssh alias of the VM running the container
267
293
  # (leave "" when target = "local" — it is unused)
@@ -270,10 +296,14 @@ memory_container = "" # the container the memory forward relays into
270
296
  # (OpenViking is the daemon container's child). On a VM running
271
297
  # the memory sidecar (the openviking table's endpoint =
272
298
  # "remote") set "quickreview-memory"; flip it back with the endpoint.
273
- remote_state_dir = "/opt/quickreview/state" # host path on ssh; inside the daemon container on local
299
+ remote_state_dir = "/opt/quickreview/state" # host path on ssh; inside the daemon container on local,
300
+ # where this default reads as the release image's /opt/qcr/state
301
+ # (the compose state volume; onboarding writes it for local)
274
302
  remote_sandbox_root = "" # "" = read the container's qcr.layout label (release: /opt/qcr, legacy: /opt/quickreview/sandbox);
275
303
  # a value here wins and is never probed
276
- sudo_docker = true # docker on the VM needs sudo (root-owned socket)
304
+ sudo_docker = true # docker on the VM needs sudo (root-owned socket). On local, onboarding
305
+ # writes false, and the TUI drops sudo by itself when this user can open
306
+ # the docker socket (a sudo prompt behind the TUI can only fail)
277
307
  poll_interval_s = 3
278
308
  stale_after_s = 90 # DATA STALE banner past this written_at age
279
309
  # (the daemon rewrites status.json every ~30s)
@@ -338,6 +368,19 @@ session_dir = "state/pi-sessions"
338
368
  # lens_cache_stagger_ms = 2500
339
369
  # lens_pass_deadline_min = 8
340
370
 
371
+ [home]
372
+ # The home: a bare `qcr` opens the app's own pinned pi, on your own pi login
373
+ # ($PI_CODING_AGENT_DIR, default ~/.pi/agent), with a panel of the
374
+ # repository's pull requests. Every key is optional.
375
+ # model — the chat's model, "provider/id". The panel counts only this
376
+ # model's provider as signed in: a login under another provider
377
+ # cannot run the chat.
378
+ # tools — "reviewer": the model may call the plugin's tools, the home's
379
+ # own home_* tools and pi's read tools (read, grep, find, ls), and
380
+ # no MCP server starts. "full": every tool pi has.
381
+ model = "openai-codex/gpt-6.1-sol"
382
+ tools = "reviewer"
383
+
341
384
  [memory]
342
385
  # Round seeding — how much memory rides each round prompt and how
343
386
  # long the daemon waits for it. Memory NEVER blocks or delays a round: past
@@ -594,7 +637,10 @@ local_embedder_threads = 1
594
637
  # (COMPANION_DEFAULTS) are the shipped configuration; uncomment to override.
595
638
  # enabled = true # `qcr tui` starts it unless --no-companion
596
639
  # container_name = "qcr-companion"
597
- # image = "qcr-companion:release" # the release image (docker/Dockerfile) in companion mode, built from the app root: qcr companion rebuild
640
+ # image = "qcr-companion:release" # the release image (docker/Dockerfile) in companion mode, built from the app root: qcr companion rebuild.
641
+ # # Left unset on a compose box (the project .env pins QCR_VERSION), a first start runs the
642
+ # # already-pulled ghcr.io/quickchatai/quickreview:<QCR_VERSION> instead of building, unless a
643
+ # # local build exists; a ghcr.io/quickchatai/quickreview tag set here is pulled, never built over
598
644
  # pihome_volume = "companion-pihome" # its OWN pi auth — never the VM's auth.json
599
645
  # session = "companion" # tmux session inside the container
600
646
  # model = "openai-codex/gpt-6.1-sol:medium"
@@ -859,7 +905,7 @@ extra_vendored_segments = [] # extra third-party markers (case-insensitive)
859
905
  # whatever — the system BEHAVES exactly as a build without the feature.
860
906
  # (The placeholder that renders empty leaves a blank line in the prompt, like
861
907
  # the sibling notes beside it.)
862
- # `qcr onboard`'s escalation step writes this section.
908
+ # The setup wizard's escalation step writes this section.
863
909
  #
864
910
  # The configuration cannot be half-done: `enabled = true` with no `targets`,
865
911
  # or a rule pointing at a login that is not a target, or a rule that declares
@@ -26,6 +26,33 @@ never as a lecture up front.
26
26
  - **On a fully-finished installation** this session doubles as a diagnostic:
27
27
  `onboard_status` re-verifies everything; report what holds and what broke.
28
28
 
29
+ ## What the person needs, and the fast path
30
+
31
+ Say this near the start, in two or three short lines. They need three things:
32
+ a **model login** (pi's `/login` opens by itself the first time — any working
33
+ OpenAI login is fine), their **GitHub sign-in** (`gh` logged in; on a Boxes VM
34
+ it already is), and **one repository**. Setup ends once the defaults are in
35
+ place and verified; the TUI then opens on the board, which lists the
36
+ repository's open pull requests — they pick one there and press `R` to review
37
+ it.
38
+
39
+ Recommend the fast path and take its defaults unless they ask otherwise:
40
+
41
+ - **topology** — `onboard_topology` with `choice: "local"` (this computer);
42
+ - **GitHub** — `onboard_github_account` with no `github_auth`: where gh is
43
+ signed in it uses their own account by itself. Call it once to get their
44
+ recent repositories, then again with `repo`;
45
+ - **ingress** — `onboard_ingress` with no `choice`: polling is the default
46
+ (the reviewer checks GitHub every few minutes; webhooks can come later);
47
+ - **the first review** — not part of setup: after `finish_and_exit` the board
48
+ lists the open pull requests, and `R` on one starts its review at once, no
49
+ label to add.
50
+
51
+ **Never ask for something no tool takes.** Every question you put to the person
52
+ is a step's input (the tool's parameters say which). If a step asks for nothing,
53
+ do not invent a question for it — run it. When a tool returns a refusal that
54
+ lists options, read those options out; do not add your own.
55
+
29
56
  ## What you teach, when
30
57
 
31
58
  - **At the start** (one short paragraph): QuickReview is a deterministic
@@ -42,33 +69,46 @@ never as a lecture up front.
42
69
  (what the reviewer learns and keeps). Explain each only when its step is in
43
70
  front of you.
44
71
 
45
- ## The last three steps
72
+ ## GitHub, in one step
73
+
74
+ `onboard_github_account` is the GitHub question. On their own account it saves
75
+ their token (0600, never shown — say so), installs a refresh every 20 minutes,
76
+ and creates the trigger labels if their account may. Read out its refresh line
77
+ as it is: on a machine without `crontab` it says what lapses and gives the
78
+ manual command. If they want a GitHub App instead, call it with
79
+ `github_auth: "app"`; the App steps then take over. Never call the App step on
80
+ the own-account route: it is skipped there.
81
+
82
+ ## The last steps
46
83
 
47
84
  - **Bring-up is slow the first time.** Say so before you run it — the tool's
48
85
  own warning is there to be read out — and let its streamed output show. A
49
86
  long build is expected, not a hang.
50
- - **The proof round is the point of the whole session.** Ask the operator for
51
- one real, open pull request of their own and have them add the trigger label
52
- to it. Then follow it. When the review comes back, show it to them and let
53
- them read it: this is their first sight of what the reviewer says, and it
54
- still cannot have posted anywhere.
55
- - **The go-live offer is theirs, and only theirs.** Read out what dry-run is
56
- and what going live means, then ask once and accept the answer. Do not
57
- advocate, do not repeat the offer, and never call the tool with a decision
58
- they did not say. Staying in dry-run is a finished, fully working
59
- installation — say so plainly if they choose it, and mention that they can
60
- flip later whenever they like.
87
+ - **The reviewer needs its own model login.** The review sessions run in the
88
+ daemon's container, and a login never transfers from this machine into it.
89
+ Once the stack is up, the LLM auth step's `daemon_login` check names the one
90
+ command that opens it; ask them to run it in a second terminal, sign in, and
91
+ tell you — then re-run the LLM auth step. Without it the first review on the
92
+ board would fail at once.
93
+ - **The first review and go-live come after setup.** `onboard_proof_round` and
94
+ `onboard_go_live` are marked "after setup": setup finishes without them. Do
95
+ not run them here unless the person asks. Say plainly that the installation
96
+ stays in dry-run (every intended GitHub write is recorded, nothing is
97
+ posted), and that going live is their decision later, from the home
98
+ (Advanced → "Dry-run or live"), once a review has shown them what it says.
61
99
 
62
100
  ## Finishing
63
101
 
64
- When every step reports done, say that `finish_and_exit` will re-verify the
65
- whole checklist one last time and, only if all green, close this session and
66
- open the TUI. If it returns red checks, that is the answer: explain them, fix
102
+ When every setup step reports done (the "after setup" ones need not be), say
103
+ that `finish_and_exit` will re-verify the whole checklist one last time and,
104
+ only if all green, close this session: the home then lists the repository's
105
+ pull requests, and they select one and press `alt+r` to review it now. If it
106
+ returns red checks, that is the answer: explain them, fix
67
107
  what can be fixed through the step tools, and try again. Never present
68
108
  onboarding as finished while anything is red, and never tell the operator to
69
109
  quit around a red check.
70
110
 
71
- Before `finish_and_exit`, pass on what comes next, as the go-live step's
72
- `next` line says it: set up the repo with `qcr setup` (or `I` on the TUI
73
- board). Until then the reviewer knows nothing about this codebase. It is a
111
+ Before `finish_and_exit`, pass on what comes next: the first review is `alt+r`
112
+ on a pull request in the home; then tune the reviewer to the repository with
113
+ the home's "Tune to this repo" (`t` on the panel). Until then the reviewer knows nothing about this codebase. It is a
74
114
  recommendation, once — never start it from here.
@@ -137,6 +137,10 @@
137
137
  "post": {
138
138
  "$ref": "#/$defs/post"
139
139
  },
140
+ "post_ready": {
141
+ "type": "string",
142
+ "description": "A finished PR review that was not posted: the file it is kept in, which a host that asks the person later posts through the gate exactly as `--to pr` would have."
143
+ },
140
144
  "run_id": {
141
145
  "type": "string",
142
146
  "description": "A detached run's id (start, status, stop)."
@@ -149,6 +153,14 @@
149
153
  "type": "string",
150
154
  "description": "What a detached run reviews."
151
155
  },
156
+ "started_at": {
157
+ "type": "number",
158
+ "description": "When a detached run was started, ms since the epoch."
159
+ },
160
+ "ended_at": {
161
+ "type": "number",
162
+ "description": "When a detached run ended (its exit or its stop), ms since the epoch; absent while it runs."
163
+ },
152
164
  "elapsed_s": {
153
165
  "type": "integer",
154
166
  "minimum": 0
@@ -165,6 +177,50 @@
165
177
  "items": {
166
178
  "type": "string"
167
179
  }
180
+ },
181
+ "live": {
182
+ "type": "object",
183
+ "description": "The running round's live log, projected: what the parent and each lens are doing now.",
184
+ "properties": {
185
+ "round": { "type": "integer", "minimum": 1 },
186
+ "parent_status": { "enum": ["active", "settled"] },
187
+ "last_activity": { "type": "string" },
188
+ "updated_at": { "type": "string" },
189
+ "active_tool": { "type": "string" },
190
+ "agents": {
191
+ "type": "array",
192
+ "items": {
193
+ "type": "object",
194
+ "required": ["agent", "status", "duration_ms", "tool_count"],
195
+ "properties": {
196
+ "agent": { "type": "string" },
197
+ "status": { "enum": ["running", "completed", "failed"] },
198
+ "duration_ms": {
199
+ "type": "number",
200
+ "minimum": 0,
201
+ "description": "The lens's time so far; a running lens's counts from its start between updates."
202
+ },
203
+ "tool_count": {
204
+ "type": "number",
205
+ "minimum": 0,
206
+ "description": "Tool calls the lens has started; a finished lens keeps its final count."
207
+ },
208
+ "current_tool": {
209
+ "type": "string",
210
+ "description": "The running (or last) tool, as `<tool>: <args>` or the bare name."
211
+ },
212
+ "current_target": {
213
+ "type": "string",
214
+ "description": "While the lens runs: the path its current tool works on, when it names one."
215
+ },
216
+ "line": {
217
+ "type": "string",
218
+ "description": "The lens as one line a person reads: `security · read src/x.ts · 7 tools · 0:41`."
219
+ }
220
+ }
221
+ }
222
+ }
223
+ }
168
224
  }
169
225
  }
170
226
  },
@@ -234,6 +290,10 @@
234
290
  "kind": {
235
291
  "enum": ["pr", "branch", "uncommitted", "diff"],
236
292
  "description": "What is reviewed: a pull request, the current branch against its base, the uncommitted working tree, or a unified diff handed in (`--diff`). Only a pr target can be posted."
293
+ },
294
+ "uncommitted": {
295
+ "const": true,
296
+ "description": "A branch target reviewed together with the working tree's uncommitted edits, as one review. Absent otherwise."
237
297
  }
238
298
  }
239
299
  },
@@ -1,5 +1,7 @@
1
- import { type ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
- import type { Runner } from "../src/plugin/session.js";
1
+ import { type ExtensionAPI, type ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
+ import type { HostAuth } from "../src/plugin/login.js";
3
+ import { type ReviewCommandDeps } from "../src/plugin/review.js";
4
+ import type { Runner, SessionUi } from "../src/plugin/session.js";
3
5
  /** What the host entry hands the plugin. */
4
6
  export interface QuickReviewConfig {
5
7
  /** The process environment, read once by the host entry. */
@@ -9,13 +11,19 @@ export interface QuickReviewConfig {
9
11
  runner: Runner;
10
12
  /** Standard output (pi's print mode shows a command's result there). */
11
13
  print: (text: string) => void;
12
- /** Test seams: the running pi's version, its agent dir, the range. */
14
+ /** Test seams: the running pi's version, its agent dir, the range, the
15
+ * review's core. */
13
16
  piVersion?: string;
14
17
  agentDir?: string;
15
18
  range?: string;
19
+ review?: ReviewCommandDeps;
16
20
  }
17
- /** The commands, in the order /qcr-setup names them. */
18
- export declare const QUICKREVIEW_COMMANDS: readonly ["review", "scan", "qcr-setup", "selfimprove"];
21
+ /** The commands, each also a skill of the same name (skills/<name>/SKILL.md). */
22
+ export declare const QUICKREVIEW_COMMANDS: readonly ["qcr-review", "qcr-scan", "qcr-setup"];
23
+ /** The host pi's auth, by the shape the plugin asks of it. */
24
+ export declare function hostAuth(ctx: ExtensionCommandContext, agentDir: string): HostAuth;
25
+ /** The session's ways to reach the person, from a command's context. */
26
+ export declare function sessionUi(pi: ExtensionAPI, ctx: ExtensionCommandContext, print: (t: string) => void): SessionUi;
19
27
  /** The plugin's extension factory over `config`. */
20
28
  export declare function createQuickReview(config: QuickReviewConfig): (pi: ExtensionAPI) => void;
21
29
  //# sourceMappingURL=quickreview.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"quickreview.d.ts","sourceRoot":"","sources":["../../extensions/quickreview.ts"],"names":[],"mappings":"AAYA,OAAO,EAGL,KAAK,YAAY,EAElB,MAAM,iCAAiC,CAAC;AAOzC,OAAO,KAAK,EAAc,MAAM,EAAa,MAAM,0BAA0B,CAAC;AAI9E,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wDAAwD;AACxD,eAAO,MAAM,oBAAoB,yDAA0D,CAAC;AAoE5F,oDAAoD;AACpD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,CAuEvF"}
1
+ {"version":3,"file":"quickreview.d.ts","sourceRoot":"","sources":["../../extensions/quickreview.ts"],"names":[],"mappings":"AAsBA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC7B,MAAM,iCAAiC,CAAC;AAIzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAc,MAAM,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAK9E,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B;wBACoB;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,kDAAmD,CAAC;AAErF,8DAA8D;AAC9D,wBAAgB,QAAQ,CAAC,GAAG,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,CA8BjF;AAKD,wEAAwE;AACxE,wBAAgB,SAAS,CACvB,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,uBAAuB,EAC5B,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,GACzB,SAAS,CA6BX;AAED,oDAAoD;AACpD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,CAmGvF"}