@quickchatai/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 (471) hide show
  1. package/README.md +137 -57
  2. package/bin/qcr.js +1 -1
  3. package/config.example.toml +60 -14
  4. package/deploy/ansible/README.md +20 -12
  5. package/deploy/ansible/inventory.example.ini +1 -1
  6. package/deploy/collect-secrets.sh +1 -1
  7. package/deploy/qcr-update.sh +1 -1
  8. package/dist/extensions/cli/home.js +14 -0
  9. package/dist/extensions/cli/home.js.map +1 -0
  10. package/dist/extensions/cli/login-route.js +5 -0
  11. package/dist/extensions/cli/login-route.js.map +1 -0
  12. package/dist/extensions/cli/selfimprove.js +18 -0
  13. package/dist/extensions/cli/selfimprove.js.map +1 -0
  14. package/dist/extensions/home.js +350 -0
  15. package/dist/extensions/home.js.map +1 -0
  16. package/dist/extensions/login-route.js +180 -0
  17. package/dist/extensions/login-route.js.map +1 -0
  18. package/dist/extensions/onboarding.js +35 -11
  19. package/dist/extensions/onboarding.js.map +1 -1
  20. package/dist/extensions/selfimprove.js +49 -0
  21. package/dist/extensions/selfimprove.js.map +1 -0
  22. package/dist/extensions/setup-scan.js +23 -592
  23. package/dist/extensions/setup-scan.js.map +1 -1
  24. package/dist/extensions/setup.js +2 -47
  25. package/dist/extensions/setup.js.map +1 -1
  26. package/dist/src/archive/restore.js +18 -15
  27. package/dist/src/archive/restore.js.map +1 -1
  28. package/dist/src/botworker.js +13 -2
  29. package/dist/src/botworker.js.map +1 -1
  30. package/dist/src/channelfs.js +3 -26
  31. package/dist/src/channelfs.js.map +1 -1
  32. package/dist/src/ciretry.js +2 -1
  33. package/dist/src/ciretry.js.map +1 -1
  34. package/dist/src/cli.js +54 -61
  35. package/dist/src/cli.js.map +1 -1
  36. package/dist/src/cliops.js +3 -2
  37. package/dist/src/cliops.js.map +1 -1
  38. package/dist/src/commands.js +25 -2
  39. package/dist/src/commands.js.map +1 -1
  40. package/dist/src/config.js +32 -2
  41. package/dist/src/config.js.map +1 -1
  42. package/dist/src/daemon.js +50 -8
  43. package/dist/src/daemon.js.map +1 -1
  44. package/dist/src/debuground.js +1 -0
  45. package/dist/src/debuground.js.map +1 -1
  46. package/dist/src/debugroundpi.js +6 -1
  47. package/dist/src/debugroundpi.js.map +1 -1
  48. package/dist/src/dispatch.js +5 -4
  49. package/dist/src/dispatch.js.map +1 -1
  50. package/dist/src/engine/caserunner-sdk.js +15 -251
  51. package/dist/src/engine/caserunner-sdk.js.map +1 -1
  52. package/dist/src/engine/debugpi.js +17 -5
  53. package/dist/src/engine/debugpi.js.map +1 -1
  54. package/dist/src/execboundary.js +10 -3
  55. package/dist/src/execboundary.js.map +1 -1
  56. package/dist/src/github.js +51 -16
  57. package/dist/src/github.js.map +1 -1
  58. package/dist/src/githubtoken.js +346 -0
  59. package/dist/src/githubtoken.js.map +1 -0
  60. package/dist/src/home/adapters.js +349 -0
  61. package/dist/src/home/adapters.js.map +1 -0
  62. package/dist/src/home/advanced.js +318 -0
  63. package/dist/src/home/advanced.js.map +1 -0
  64. package/dist/src/home/advancedtools.js +57 -0
  65. package/dist/src/home/advancedtools.js.map +1 -0
  66. package/dist/src/home/autoreview.js +325 -0
  67. package/dist/src/home/autoreview.js.map +1 -0
  68. package/dist/src/home/daemonstatus.js +32 -0
  69. package/dist/src/home/daemonstatus.js.map +1 -0
  70. package/dist/src/home/devicelogin.js +61 -0
  71. package/dist/src/home/devicelogin.js.map +1 -0
  72. package/dist/src/home/launch.js +202 -0
  73. package/dist/src/home/launch.js.map +1 -0
  74. package/dist/src/home/loginowner.js +205 -0
  75. package/dist/src/home/loginowner.js.map +1 -0
  76. package/dist/src/home/memory.js +122 -0
  77. package/dist/src/home/memory.js.map +1 -0
  78. package/dist/src/home/model.js +811 -0
  79. package/dist/src/home/model.js.map +1 -0
  80. package/dist/src/home/panel.js +520 -0
  81. package/dist/src/home/panel.js.map +1 -0
  82. package/dist/src/home/ports.js +19 -0
  83. package/dist/src/home/ports.js.map +1 -0
  84. package/dist/src/home/review.js +163 -0
  85. package/dist/src/home/review.js.map +1 -0
  86. package/dist/src/home/reviews.js +478 -0
  87. package/dist/src/home/reviews.js.map +1 -0
  88. package/dist/src/home/setup.js +507 -0
  89. package/dist/src/home/setup.js.map +1 -0
  90. package/dist/src/home/setupadapters.js +214 -0
  91. package/dist/src/home/setupadapters.js.map +1 -0
  92. package/dist/src/home/setupcard.js +199 -0
  93. package/dist/src/home/setupcard.js.map +1 -0
  94. package/dist/src/home/setuptools.js +45 -0
  95. package/dist/src/home/setuptools.js.map +1 -0
  96. package/dist/src/home/spend.js +160 -0
  97. package/dist/src/home/spend.js.map +1 -0
  98. package/dist/src/home/switches.js +209 -0
  99. package/dist/src/home/switches.js.map +1 -0
  100. package/dist/src/home/switchon.js +439 -0
  101. package/dist/src/home/switchon.js.map +1 -0
  102. package/dist/src/home/toolnames.js +41 -0
  103. package/dist/src/home/toolnames.js.map +1 -0
  104. package/dist/src/home/tune.js +341 -0
  105. package/dist/src/home/tune.js.map +1 -0
  106. package/dist/src/home/words.js +7 -0
  107. package/dist/src/home/words.js.map +1 -0
  108. package/dist/src/homes.js +14 -0
  109. package/dist/src/homes.js.map +1 -1
  110. package/dist/src/install.js +1 -1
  111. package/dist/src/install.js.map +1 -1
  112. package/dist/src/ipc/workerspec.js +8 -0
  113. package/dist/src/ipc/workerspec.js.map +1 -1
  114. package/dist/src/live/publish.js +1 -1
  115. package/dist/src/live/publish.js.map +1 -1
  116. package/dist/src/livecli.js +1 -1
  117. package/dist/src/livecli.js.map +1 -1
  118. package/dist/src/loginhint.js +8 -3
  119. package/dist/src/loginhint.js.map +1 -1
  120. package/dist/src/loginrefresh/handover.js +121 -0
  121. package/dist/src/loginrefresh/handover.js.map +1 -0
  122. package/dist/src/loginrefresh/lock.js +54 -3
  123. package/dist/src/loginrefresh/lock.js.map +1 -1
  124. package/dist/src/loginrefresh/pirefresh.js +3 -0
  125. package/dist/src/loginrefresh/pirefresh.js.map +1 -1
  126. package/dist/src/loginrefresh/refresher.js +33 -5
  127. package/dist/src/loginrefresh/refresher.js.map +1 -1
  128. package/dist/src/loginrefresh/supervisor.js +18 -1
  129. package/dist/src/loginrefresh/supervisor.js.map +1 -1
  130. package/dist/src/npmverbs.js +46 -14
  131. package/dist/src/npmverbs.js.map +1 -1
  132. package/dist/src/onboard/choices.js +35 -4
  133. package/dist/src/onboard/choices.js.map +1 -1
  134. package/dist/src/onboard/engine.js +32 -306
  135. package/dist/src/onboard/engine.js.map +1 -1
  136. package/dist/src/onboard/pipin.js +22 -0
  137. package/dist/src/onboard/pipin.js.map +1 -0
  138. package/dist/src/onboard/stepforward.js +41 -0
  139. package/dist/src/onboard/stepforward.js.map +1 -0
  140. package/dist/src/onboard/steps/appslug.js +4 -1
  141. package/dist/src/onboard/steps/appslug.js.map +1 -1
  142. package/dist/src/onboard/steps/bringup.js +3 -2
  143. package/dist/src/onboard/steps/bringup.js.map +1 -1
  144. package/dist/src/onboard/steps/compose.js +29 -0
  145. package/dist/src/onboard/steps/compose.js.map +1 -1
  146. package/dist/src/onboard/steps/configfill.js +120 -39
  147. package/dist/src/onboard/steps/configfill.js.map +1 -1
  148. package/dist/src/onboard/steps/githubaccount.js +595 -0
  149. package/dist/src/onboard/steps/githubaccount.js.map +1 -0
  150. package/dist/src/onboard/steps/githubapp.js +65 -7
  151. package/dist/src/onboard/steps/githubapp.js.map +1 -1
  152. package/dist/src/onboard/steps/golive.js +2 -0
  153. package/dist/src/onboard/steps/golive.js.map +1 -1
  154. package/dist/src/onboard/steps/index.js +11 -0
  155. package/dist/src/onboard/steps/index.js.map +1 -1
  156. package/dist/src/onboard/steps/ingress.js +80 -25
  157. package/dist/src/onboard/steps/ingress.js.map +1 -1
  158. package/dist/src/onboard/steps/llmauth.js +103 -30
  159. package/dist/src/onboard/steps/llmauth.js.map +1 -1
  160. package/dist/src/onboard/steps/loginshare.js +213 -0
  161. package/dist/src/onboard/steps/loginshare.js.map +1 -0
  162. package/dist/src/onboard/steps/memory.js +67 -3
  163. package/dist/src/onboard/steps/memory.js.map +1 -1
  164. package/dist/src/onboard/steps/proof.js +366 -56
  165. package/dist/src/onboard/steps/proof.js.map +1 -1
  166. package/dist/src/onboard/steps/repoconfig.js +72 -0
  167. package/dist/src/onboard/steps/repoconfig.js.map +1 -0
  168. package/dist/src/onboard/steps/topology.js +6 -6
  169. package/dist/src/onboard/steps/topology.js.map +1 -1
  170. package/dist/src/onboard/steps/transport.js +9 -1
  171. package/dist/src/onboard/steps/transport.js.map +1 -1
  172. package/dist/src/onboard/steps/tuiroute.js +102 -0
  173. package/dist/src/onboard/steps/tuiroute.js.map +1 -0
  174. package/dist/src/onboard/steps/verifyup.js +17 -1
  175. package/dist/src/onboard/steps/verifyup.js.map +1 -1
  176. package/dist/src/onboard/toolnames.js +30 -0
  177. package/dist/src/onboard/toolnames.js.map +1 -0
  178. package/dist/src/operatorwrite.js +23 -0
  179. package/dist/src/operatorwrite.js.map +1 -0
  180. package/dist/src/outcomes.js +4 -1
  181. package/dist/src/outcomes.js.map +1 -1
  182. package/dist/src/piagentdir.js +13 -0
  183. package/dist/src/piagentdir.js.map +1 -0
  184. package/dist/src/pilogin.js +31 -16
  185. package/dist/src/pilogin.js.map +1 -1
  186. package/dist/src/posting-journal.js +2 -1
  187. package/dist/src/posting-journal.js.map +1 -1
  188. package/dist/src/posting-outbox.js +6 -2
  189. package/dist/src/posting-outbox.js.map +1 -1
  190. package/dist/src/posting-receipt.js +14 -1
  191. package/dist/src/posting-receipt.js.map +1 -1
  192. package/dist/src/qcrbin.js +16 -11
  193. package/dist/src/qcrbin.js.map +1 -1
  194. package/dist/src/recheck.js +2 -1
  195. package/dist/src/recheck.js.map +1 -1
  196. package/dist/src/reconcile.js +22 -2
  197. package/dist/src/reconcile.js.map +1 -1
  198. package/dist/src/reviewargs.js +122 -0
  199. package/dist/src/reviewargs.js.map +1 -0
  200. package/dist/src/reviewcli.js +7 -161
  201. package/dist/src/reviewcli.js.map +1 -1
  202. package/dist/src/reviewdetach.js +76 -11
  203. package/dist/src/reviewdetach.js.map +1 -1
  204. package/dist/src/reviewhistory.js +32 -6
  205. package/dist/src/reviewhistory.js.map +1 -1
  206. package/dist/src/reviewnow.js +45 -0
  207. package/dist/src/reviewnow.js.map +1 -0
  208. package/dist/src/scancli.js +39 -691
  209. package/dist/src/scancli.js.map +1 -1
  210. package/dist/src/selfimprove.js +66 -0
  211. package/dist/src/selfimprove.js.map +1 -0
  212. package/dist/src/setup/adapters.js +5 -223
  213. package/dist/src/setup/adapters.js.map +1 -1
  214. package/dist/src/setup/caserunner.js +15 -249
  215. package/dist/src/setup/caserunner.js.map +1 -1
  216. package/dist/src/setup/engine.js +32 -341
  217. package/dist/src/setup/engine.js.map +1 -1
  218. package/dist/src/setup/facts.js +3 -592
  219. package/dist/src/setup/facts.js.map +1 -1
  220. package/dist/src/setup/findings.js +3 -947
  221. package/dist/src/setup/findings.js.map +1 -1
  222. package/dist/src/setup/presentation.js +3 -8
  223. package/dist/src/setup/presentation.js.map +1 -1
  224. package/dist/src/setup/scan.js +3 -724
  225. package/dist/src/setup/scan.js.map +1 -1
  226. package/dist/src/setup/scanbuild.js +9 -92
  227. package/dist/src/setup/scanbuild.js.map +1 -1
  228. package/dist/src/setup/scanlease.js +3 -250
  229. package/dist/src/setup/scanlease.js.map +1 -1
  230. package/dist/src/setup/scanreport.js +3 -288
  231. package/dist/src/setup/scanreport.js.map +1 -1
  232. package/dist/src/setup/scanrun.js +3 -1732
  233. package/dist/src/setup/scanrun.js.map +1 -1
  234. package/dist/src/setup/scantree.js +3 -256
  235. package/dist/src/setup/scantree.js.map +1 -1
  236. package/dist/src/setup/stage2request.js +3 -258
  237. package/dist/src/setup/stage2request.js.map +1 -1
  238. package/dist/src/setup/unitcut.js +3 -436
  239. package/dist/src/setup/unitcut.js.map +1 -1
  240. package/dist/src/state.js +2 -0
  241. package/dist/src/state.js.map +1 -1
  242. package/dist/src/statemachine.js +4 -1
  243. package/dist/src/statemachine.js.map +1 -1
  244. package/dist/src/takeover.js +1 -0
  245. package/dist/src/takeover.js.map +1 -1
  246. package/dist/src/takeoverpi.js +15 -1
  247. package/dist/src/takeoverpi.js.map +1 -1
  248. package/dist/src/tui/app.js +49 -0
  249. package/dist/src/tui/app.js.map +1 -1
  250. package/dist/src/tui/board.js +88 -12
  251. package/dist/src/tui/board.js.map +1 -1
  252. package/dist/src/tui/cmdbar.js +4 -1
  253. package/dist/src/tui/cmdbar.js.map +1 -1
  254. package/dist/src/tui/companion.js +76 -11
  255. package/dist/src/tui/companion.js.map +1 -1
  256. package/dist/src/tui/connect.js +7 -1
  257. package/dist/src/tui/connect.js.map +1 -1
  258. package/dist/src/tui/deploytab.js +2 -2
  259. package/dist/src/tui/deploytab.js.map +1 -1
  260. package/dist/src/tui/filters.js +5 -2
  261. package/dist/src/tui/filters.js.map +1 -1
  262. package/dist/src/tui/ghread.js +61 -5
  263. package/dist/src/tui/ghread.js.map +1 -1
  264. package/dist/src/tui/index.js +109 -20
  265. package/dist/src/tui/index.js.map +1 -1
  266. package/dist/src/tui/memforward.js +39 -2
  267. package/dist/src/tui/memforward.js.map +1 -1
  268. package/dist/src/tui/memory.js +3 -16
  269. package/dist/src/tui/memory.js.map +1 -1
  270. package/dist/src/tui/memoryurl.js +22 -0
  271. package/dist/src/tui/memoryurl.js.map +1 -0
  272. package/dist/src/tui/model.js +25 -0
  273. package/dist/src/tui/model.js.map +1 -1
  274. package/dist/src/tui/prpause.js +7 -0
  275. package/dist/src/tui/prpause.js.map +1 -1
  276. package/dist/src/tui/remote.js +7 -1
  277. package/dist/src/tui/remote.js.map +1 -1
  278. package/dist/src/tui/route.js +143 -0
  279. package/dist/src/tui/route.js.map +1 -0
  280. package/dist/src/tui/setupstate.js +32 -0
  281. package/dist/src/tui/setupstate.js.map +1 -0
  282. package/dist/src/tui/sshtriage.js +102 -5
  283. package/dist/src/tui/sshtriage.js.map +1 -1
  284. package/dist/src/tui/theme.js +2 -1
  285. package/dist/src/tui/theme.js.map +1 -1
  286. package/dist/src/tui/unwedge.js +2 -12
  287. package/dist/src/tui/unwedge.js.map +1 -1
  288. package/dist/src/verdicts.js +17 -5
  289. package/dist/src/verdicts.js.map +1 -1
  290. package/dist/src/version.js +1 -1
  291. package/dist/src/version.js.map +1 -1
  292. package/dist/src/webhook.js +12 -1
  293. package/dist/src/webhook.js.map +1 -1
  294. package/dist/src/wire.js +34 -8
  295. package/dist/src/wire.js.map +1 -1
  296. package/dist/src/workerworld.js +11 -1
  297. package/dist/src/workerworld.js.map +1 -1
  298. package/docker/README.md +1 -1
  299. package/docker/companion/entrypoint.sh +20 -1
  300. package/docker/entrypoint.sh +57 -6
  301. package/docker-compose.yml +16 -1
  302. package/extensions/cli/home.ts +14 -0
  303. package/extensions/cli/login-route.ts +10 -0
  304. package/extensions/cli/selfimprove.ts +18 -0
  305. package/extensions/home.ts +484 -0
  306. package/extensions/login-route.ts +220 -0
  307. package/extensions/onboarding.ts +41 -11
  308. package/extensions/selfimprove.ts +65 -0
  309. package/extensions/setup-scan.ts +79 -766
  310. package/extensions/setup.ts +14 -70
  311. package/package.json +6 -4
  312. package/prompts/onboarding.md +58 -18
  313. package/schemas/review-result.v1.json +60 -0
  314. package/scripts/deploy.sh +8 -6
  315. package/scripts/mint-token.sh +25 -4
  316. package/scripts/qcr-host.sh +28 -5
  317. package/scripts/vm-ghcr-login.sh +7 -4
  318. package/src/archive/restore.ts +18 -21
  319. package/src/botworker.ts +13 -2
  320. package/src/channelfs.ts +3 -26
  321. package/src/ciretry.ts +2 -1
  322. package/src/cli.ts +59 -67
  323. package/src/cliops.ts +3 -2
  324. package/src/commands.ts +28 -2
  325. package/src/config.ts +62 -4
  326. package/src/daemon.ts +58 -7
  327. package/src/debuground.ts +3 -0
  328. package/src/debugroundpi.ts +12 -1
  329. package/src/dispatch.ts +5 -4
  330. package/src/engine/caserunner-sdk.ts +29 -314
  331. package/src/engine/debugpi.ts +17 -5
  332. package/src/execboundary.ts +16 -4
  333. package/src/github.ts +57 -15
  334. package/src/githubtoken.ts +435 -0
  335. package/src/home/adapters.ts +418 -0
  336. package/src/home/advanced.ts +421 -0
  337. package/src/home/advancedtools.ts +96 -0
  338. package/src/home/autoreview.ts +385 -0
  339. package/src/home/daemonstatus.ts +55 -0
  340. package/src/home/devicelogin.ts +107 -0
  341. package/src/home/launch.ts +257 -0
  342. package/src/home/loginowner.ts +248 -0
  343. package/src/home/memory.ts +176 -0
  344. package/src/home/model.ts +965 -0
  345. package/src/home/panel.ts +666 -0
  346. package/src/home/ports.ts +338 -0
  347. package/src/home/review.ts +206 -0
  348. package/src/home/reviews.ts +565 -0
  349. package/src/home/setup.ts +689 -0
  350. package/src/home/setupadapters.ts +217 -0
  351. package/src/home/setupcard.ts +288 -0
  352. package/src/home/setuptools.ts +57 -0
  353. package/src/home/spend.ts +194 -0
  354. package/src/home/switches.ts +293 -0
  355. package/src/home/switchon.ts +554 -0
  356. package/src/home/toolnames.ts +46 -0
  357. package/src/home/tune.ts +405 -0
  358. package/src/home/words.ts +8 -0
  359. package/src/homes.ts +17 -0
  360. package/src/install.ts +1 -1
  361. package/src/ipc/workerspec.ts +15 -0
  362. package/src/live/publish.ts +4 -1
  363. package/src/livecli.ts +6 -1
  364. package/src/loginhint.ts +8 -3
  365. package/src/loginrefresh/handover.ts +138 -0
  366. package/src/loginrefresh/lock.ts +72 -3
  367. package/src/loginrefresh/pirefresh.ts +3 -0
  368. package/src/loginrefresh/refresher.ts +34 -5
  369. package/src/loginrefresh/supervisor.ts +25 -2
  370. package/src/npmverbs.ts +55 -13
  371. package/src/onboard/choices.ts +40 -4
  372. package/src/onboard/engine.ts +70 -421
  373. package/src/onboard/pipin.ts +31 -0
  374. package/src/onboard/stepforward.ts +61 -0
  375. package/src/onboard/steps/appslug.ts +4 -1
  376. package/src/onboard/steps/bringup.ts +3 -2
  377. package/src/onboard/steps/compose.ts +31 -0
  378. package/src/onboard/steps/configfill.ts +144 -40
  379. package/src/onboard/steps/githubaccount.ts +716 -0
  380. package/src/onboard/steps/githubapp.ts +92 -8
  381. package/src/onboard/steps/golive.ts +2 -0
  382. package/src/onboard/steps/index.ts +11 -0
  383. package/src/onboard/steps/ingress.ts +98 -31
  384. package/src/onboard/steps/llmauth.ts +114 -29
  385. package/src/onboard/steps/loginshare.ts +258 -0
  386. package/src/onboard/steps/memory.ts +76 -3
  387. package/src/onboard/steps/proof.ts +473 -55
  388. package/src/onboard/steps/repoconfig.ts +85 -0
  389. package/src/onboard/steps/topology.ts +7 -6
  390. package/src/onboard/steps/transport.ts +15 -0
  391. package/src/onboard/steps/tuiroute.ts +119 -0
  392. package/src/onboard/steps/verifyup.ts +20 -1
  393. package/src/onboard/toolnames.ts +34 -0
  394. package/src/operatorwrite.ts +25 -0
  395. package/src/outcomes.ts +8 -1
  396. package/src/piagentdir.ts +12 -0
  397. package/src/pilogin.ts +32 -16
  398. package/src/posting-journal.ts +6 -1
  399. package/src/posting-outbox.ts +10 -2
  400. package/src/posting-receipt.ts +17 -0
  401. package/src/qcrbin.ts +16 -11
  402. package/src/recheck.ts +2 -1
  403. package/src/reconcile.ts +29 -3
  404. package/src/reviewargs.ts +119 -0
  405. package/src/reviewcli.ts +6 -167
  406. package/src/reviewdetach.ts +107 -13
  407. package/src/reviewhistory.ts +20 -6
  408. package/src/reviewnow.ts +76 -0
  409. package/src/scancli.ts +75 -826
  410. package/src/selfimprove.ts +90 -0
  411. package/src/setup/adapters.ts +13 -221
  412. package/src/setup/caserunner.ts +34 -273
  413. package/src/setup/engine.ts +62 -496
  414. package/src/setup/facts.ts +3 -627
  415. package/src/setup/findings.ts +3 -1264
  416. package/src/setup/presentation.ts +3 -18
  417. package/src/setup/scan.ts +3 -1033
  418. package/src/setup/scanbuild.ts +20 -114
  419. package/src/setup/scanlease.ts +3 -297
  420. package/src/setup/scanreport.ts +3 -373
  421. package/src/setup/scanrun.ts +3 -2268
  422. package/src/setup/scantree.ts +3 -259
  423. package/src/setup/stage2request.ts +3 -347
  424. package/src/setup/unitcut.ts +3 -523
  425. package/src/state.ts +43 -0
  426. package/src/statemachine.ts +4 -1
  427. package/src/takeover.ts +5 -0
  428. package/src/takeoverpi.ts +16 -2
  429. package/src/tui/app.ts +47 -0
  430. package/src/tui/board.ts +111 -14
  431. package/src/tui/cmdbar.ts +4 -1
  432. package/src/tui/companion.ts +80 -11
  433. package/src/tui/connect.ts +7 -1
  434. package/src/tui/deploytab.ts +2 -2
  435. package/src/tui/filters.ts +7 -3
  436. package/src/tui/ghread.ts +74 -7
  437. package/src/tui/index.ts +117 -23
  438. package/src/tui/memforward.ts +52 -3
  439. package/src/tui/memory.ts +3 -15
  440. package/src/tui/memoryurl.ts +22 -0
  441. package/src/tui/model.ts +36 -2
  442. package/src/tui/prpause.ts +11 -2
  443. package/src/tui/remote.ts +9 -1
  444. package/src/tui/route.ts +173 -0
  445. package/src/tui/setupstate.ts +56 -0
  446. package/src/tui/sshtriage.ts +127 -6
  447. package/src/tui/theme.ts +2 -1
  448. package/src/tui/unwedge.ts +2 -14
  449. package/src/verdicts.ts +23 -5
  450. package/src/version.ts +1 -1
  451. package/src/webhook.ts +10 -1
  452. package/src/wire.ts +42 -9
  453. package/src/workerworld.ts +16 -2
  454. package/dist/src/live/projection.js +0 -450
  455. package/dist/src/live/projection.js.map +0 -1
  456. package/dist/src/live/read.js +0 -60
  457. package/dist/src/live/read.js.map +0 -1
  458. package/dist/src/onboard/launch.js +0 -83
  459. package/dist/src/onboard/launch.js.map +0 -1
  460. package/dist/src/setup/ledger.js +0 -207
  461. package/dist/src/setup/ledger.js.map +0 -1
  462. package/dist/src/setup/stage2.js +0 -617
  463. package/dist/src/setup/stage2.js.map +0 -1
  464. package/dist/src/setup/textsniff.js +0 -89
  465. package/dist/src/setup/textsniff.js.map +0 -1
  466. package/src/live/projection.ts +0 -491
  467. package/src/live/read.ts +0 -86
  468. package/src/onboard/launch.ts +0 -115
  469. package/src/setup/ledger.ts +0 -324
  470. package/src/setup/stage2.ts +0 -926
  471. package/src/setup/textsniff.ts +0 -95
@@ -0,0 +1,338 @@
1
+ // The home's ports: everything the home (extensions/home.ts) knows about the
2
+ // world comes through one of these. The env shim (extensions/cli/home.ts)
3
+ // builds the real ones (src/home/adapters.ts); tests build fakes.
4
+ //
5
+ // Every read answers a `Known<T>`: a value, or `unknown` with the reason. A
6
+ // source that cannot be read is never a zero, an empty list or a default
7
+ // (invariant 9): the panel renders it Unknown and the `home_status` tool
8
+ // reports it as null.
9
+ //
10
+ // The home reads pi login, GitHub, the repository, the clock and the reviews
11
+ // (the app's detached runs, its per-target review state and the daemon's
12
+ // rounds). Auto-review, memory and spend are typed here so the panel's rows
13
+ // exist from the start; until each has its adapter, the stubs in adapters.ts
14
+ // answer unknown. Auto-review and memory carry their switches as
15
+ // optional controls.
16
+
17
+ /** A read that worked, or one that did not and why. */
18
+ export type Known<T> = { kind: "known"; value: T } | { kind: "unknown"; why: string };
19
+
20
+ /** A read still in flight: the panel shows it as being checked. */
21
+ export type Pending = { kind: "pending" };
22
+
23
+ /** A slot of the home's state: not read yet, read, or unreadable. */
24
+ export type Slot<T> = Pending | Known<T>;
25
+
26
+ export const known = <T>(value: T): Known<T> => ({ kind: "known", value });
27
+ export const unknown = (why: string): Known<never> => ({ kind: "unknown", why });
28
+ export const PENDING: Pending = { kind: "pending" };
29
+
30
+ /** The pi login of the pi home the chat runs in. */
31
+ export interface PiLoginPort {
32
+ /** The providers pi holds a credential for in that home's auth file; an
33
+ * empty list when it holds none. Provider ids only, never a token. */
34
+ providers(): Promise<Known<readonly string[]>>;
35
+ }
36
+
37
+ /** Who refreshes the box's one OpenAI login, and whether it still works
38
+ * (src/home/loginowner.ts). */
39
+ export interface LoginHealth {
40
+ /** "auto-review": the daemon's refresher holds it (auto-review runs on this
41
+ * machine); "home": the home's own pi refreshes it, by pi's own rule. */
42
+ refresher: "auto-review" | "home";
43
+ /** Why it no longer works ("login expired"), from the refresher's record;
44
+ * absent while it works or while nothing says otherwise. */
45
+ expired?: string;
46
+ /** When the refresher last looked at it, ms since the epoch. */
47
+ checkedAt?: number;
48
+ }
49
+
50
+ /** The handover around a re-login: the refresher paused, then released. */
51
+ export type LoginHold = { ok: true; held: boolean; release(): void } | { ok: false; why: string };
52
+
53
+ /** The box's one login, beside the pi that holds it. */
54
+ export interface LoginOwnerPort {
55
+ health(): Promise<Known<LoginHealth>>;
56
+ /** Pause the refresher, when one runs, for a login; release it after. */
57
+ hold(): Promise<LoginHold>;
58
+ }
59
+
60
+ /** One open pull request, as `gh pr list --json` gives it. */
61
+ export interface OpenPull {
62
+ number: number;
63
+ title: string;
64
+ author: string;
65
+ /** ISO time of the last update. */
66
+ updatedAt: string;
67
+ isDraft: boolean;
68
+ additions: number;
69
+ deletions: number;
70
+ changedFiles: number;
71
+ headRefName: string;
72
+ /** The head commit: a price is cached by it. Empty when gh gave none. */
73
+ headSha: string;
74
+ }
75
+
76
+ export interface GithubPort {
77
+ /** The `gh` account's login; null when `gh` is not signed in. */
78
+ user(): Promise<Known<string | null>>;
79
+ /** The repository's open pull requests (closed and merged ones never). */
80
+ openPulls(repo: string): Promise<Known<readonly OpenPull[]>>;
81
+ /** Open one pull request in the person's browser. */
82
+ openInBrowser(repo: string, pr: number): Promise<{ ok: true } | { ok: false; why: string }>;
83
+ }
84
+
85
+ /** The repository the home reviews (the app config's `[github] repo`). */
86
+ export interface RepoPort {
87
+ /** `owner/name`; null when no repository is configured. */
88
+ repo(): Promise<Known<string | null>>;
89
+ }
90
+
91
+ export interface ClockPort {
92
+ /** Milliseconds since the epoch. */
93
+ now(): number;
94
+ }
95
+
96
+ /** The latest review of one pull request. */
97
+ export interface PrReview {
98
+ /** How many findings it raised; null when its source does not say
99
+ * (auto-review's status counts rounds, not findings). */
100
+ findings: number | null;
101
+ /** How many of the findings are high severity (P0, P1); null as above. */
102
+ high: number | null;
103
+ /** Who ran it: the person from the home, or auto-review. */
104
+ by: "you" | "auto";
105
+ /** When it finished, ms since the epoch. */
106
+ at: number;
107
+ /** The findings themselves, when the review's result is at hand. */
108
+ list?: readonly ReviewFinding[];
109
+ /** The review's markdown report, when it wrote one. */
110
+ report?: string;
111
+ /** How long it took, and what it cost (null: the result does not say). */
112
+ tookMs?: number;
113
+ costUsd?: number | null;
114
+ }
115
+
116
+ /** One finding as the home shows it. */
117
+ export interface ReviewFinding {
118
+ /** The reviewer's severity, as written: P0 … P3, nit. */
119
+ severity: string;
120
+ path: string | null;
121
+ line: number | null;
122
+ title: string;
123
+ /** The lens agent that raised it. */
124
+ lens: string | null;
125
+ }
126
+
127
+ /** The reviewer's preview of one pull request: its plan, its price and the
128
+ * key that starts it over the repo's limit. */
129
+ export interface ReviewQuote {
130
+ estimateUsd: number;
131
+ /** The hard stop; null: none. */
132
+ capUsd: number | null;
133
+ key: string;
134
+ /** The lens agents the plan runs, the validator among them. */
135
+ lenses: readonly string[];
136
+ files: number;
137
+ /** The head the quote is of. */
138
+ headSha: string | null;
139
+ }
140
+
141
+ /** One lens of a running review, from its live log. */
142
+ export interface LiveLens {
143
+ /** The lens agent (`pass-security--sol-high`). */
144
+ agent: string;
145
+ /** running, completed, failed, or another word the log uses. */
146
+ status: string;
147
+ toolCount: number;
148
+ durationMs: number;
149
+ currentTool?: string;
150
+ currentTarget?: string;
151
+ /** The lens's activity as one line (packages/pi-plugin/src/live/lensline.ts). */
152
+ line: string;
153
+ }
154
+
155
+ export type ReviewRunState = "running" | "done" | "failed" | "stopped";
156
+
157
+ /** A detached review run, as `qcr review status` reports it. */
158
+ export interface ReviewRunStatus {
159
+ runId: string;
160
+ state: ReviewRunState;
161
+ /** The pull request it reviews, when it is one. */
162
+ repo: string | null;
163
+ pr: number | null;
164
+ /** When it was started, ms since the epoch. */
165
+ startedAt: number;
166
+ /** When it ended, ms since the epoch (the result's time); absent while it runs. */
167
+ endedAt?: number;
168
+ /** Where its report is written. */
169
+ report?: string;
170
+ /** While it runs: the lenses its live log names, and what the round says
171
+ * it is doing. Absent until the log exists. */
172
+ live?: { lastActivity: string; lenses: readonly LiveLens[] };
173
+ /** Once it has ended: what its result says. */
174
+ result?: {
175
+ findings: readonly ReviewFinding[];
176
+ /** What it cost; null when the result does not say. */
177
+ costUsd: number | null;
178
+ /** The finished review kept for a later post (the result's `post_ready`). */
179
+ postFile?: string;
180
+ /** It posted already (its own `--to pr`). */
181
+ posted?: boolean;
182
+ };
183
+ /** Why it failed or stopped. */
184
+ errors: readonly string[];
185
+ }
186
+
187
+ export type Outcome<T> = ({ ok: true } & T) | { ok: false; why: string };
188
+
189
+ /** The reviewer, as the home drives it: the app's detached runs. */
190
+ export interface ReviewsPort {
191
+ /** The latest review per open pull request of `repo` the person ran (the
192
+ * home's finished runs and the app's per-target review state), by number.
193
+ * A PR absent from the map has no review. */
194
+ latest(repo: string): Promise<Known<ReadonlyMap<number, PrReview>>>;
195
+ /** The pull requests of `repo` the daemon finished a review round of
196
+ * (auto-review's half of the Reviewed list): a round still running or one
197
+ * that failed is no review. */
198
+ autoRounds(repo: string): Promise<Known<ReadonlyMap<number, PrReview>>>;
199
+ /** Price one pull request: the reviewer's own preview. A stop abandons it. */
200
+ preview(
201
+ repo: string,
202
+ pr: number,
203
+ o?: { signal?: AbortSignal },
204
+ ): Promise<Outcome<{ quote: ReviewQuote }>>;
205
+ /** Start a detached review with the preview's key, writing its report to a
206
+ * file in the state home. It never posts. */
207
+ start(repo: string, pr: number, key: string): Promise<Outcome<{ runId: string; report: string }>>;
208
+ status(runId: string): Promise<Known<ReviewRunStatus>>;
209
+ stop(runId: string): Promise<Outcome<object>>;
210
+ /** Every run of `repo` the registry holds, oldest first: what the home
211
+ * re-attaches to when it opens. */
212
+ runs(repo: string): Promise<Known<readonly ReviewRunStatus[]>>;
213
+ /** Post a finished review kept for later: one comment-only review through
214
+ * the gate, with the install's dry_run. `line` says what happened. */
215
+ post(postFile: string): Promise<Outcome<{ line: string }>>;
216
+ /** The install keeps dry_run on: a post is recorded, not sent. */
217
+ dryRun(): Promise<Known<boolean>>;
218
+ }
219
+
220
+ /** Auto-review's label: Unknown is the port answering unknown. */
221
+ export type AutoReviewState = "off" | "starting" | "on-live" | "on-dry" | "paused-login" | "broken";
222
+
223
+ export interface AutoReviewStatus {
224
+ state: AutoReviewState;
225
+ /** Why it is broken or paused, in plain words. */
226
+ cause?: string;
227
+ /** The daemon's last poll, ms since the epoch. */
228
+ checkedAt?: number;
229
+ }
230
+
231
+ export interface AutoReviewPort {
232
+ status(): Promise<Known<AutoReviewStatus>>;
233
+ /** What auto-review picks up besides a review request: the trigger label
234
+ * (`[github] trigger_label`). Absent: the home does not say. */
235
+ trigger?(): Promise<Known<string>>;
236
+ /** The switch (src/home/autoreview.ts). Absent: the home only shows it. */
237
+ control?: AutoReviewControl;
238
+ }
239
+
240
+ export type MemoryState = "off" | "starting" | "on";
241
+
242
+ export interface MemoryPort {
243
+ status(): Promise<Known<MemoryState>>;
244
+ /** The switch (src/home/memory.ts). Absent: the home only shows it. */
245
+ control?: MemoryControl;
246
+ }
247
+
248
+ // ---- the switches -------------------------------------------------------
249
+
250
+ /** What a switch did, in plain words. */
251
+ export type SwitchResult = { ok: true; detail: string } | { ok: false; detail: string };
252
+
253
+ /** A round the daemon is running now. */
254
+ export interface RunningRound {
255
+ pr: number;
256
+ round: number;
257
+ }
258
+
259
+ /** The person's answers to switch-on's questions: every one theirs, asked
260
+ * in the home (src/home/switches.ts). */
261
+ export interface SwitchOnAnswers {
262
+ /** Memory with it: true turns it on, false keeps it off, null leaves it
263
+ * as it is (it was not offered). */
264
+ memory: boolean | null;
265
+ /** The one explicit confirm. Only a person's answer in the home sets it.
266
+ * Switch-on comes up in dry-run: the go-live has a confirm of its own. */
267
+ confirmed: true;
268
+ }
269
+
270
+ /** The proof round the go-live step demands, as recorded. */
271
+ export interface ProofRound {
272
+ pr: number;
273
+ verdict: string;
274
+ }
275
+
276
+ export interface SwitchOnOutcome {
277
+ ok: boolean;
278
+ /** Posting live after it: true, false (dry-run), null when unreadable. */
279
+ live: boolean | null;
280
+ /** What happened, for the notice. */
281
+ detail: string;
282
+ /** Each step that ran or was skipped, in order: `id: what it said`. */
283
+ steps: readonly string[];
284
+ }
285
+
286
+ export interface AutoReviewControl {
287
+ /** The machine checks (Docker, disk, ports): run before anything is asked. */
288
+ machineChecks(): Promise<SwitchResult>;
289
+ /** The config's `dry_run` now: whether it posts live once on. */
290
+ dryRun(): Promise<Known<boolean>>;
291
+ /** Run switch-on's steps in order; `progress` gets each line as it comes. */
292
+ switchOn(answers: SwitchOnAnswers, progress?: (line: string) => void): Promise<SwitchOnOutcome>;
293
+ /** The proof round the checklist records; null when there is none yet. */
294
+ proof(): Promise<ProofRound | null>;
295
+ /** The proof round on pull request `pr`, from dry-run: the daemon reviews
296
+ * it now and the detail is the review it would have posted. */
297
+ proofRound(pr: number, progress?: (line: string) => void): Promise<SwitchResult>;
298
+ /** Go live from dry-run: the go-live step with the person's go-live
299
+ * confirm, asked after the proof round. */
300
+ goLive(answers: { confirmed: true }): Promise<SwitchResult>;
301
+ /** The rounds running now, for switch-off's warning. */
302
+ running(): Promise<Known<readonly RunningRound[]>>;
303
+ /** Stop the daemon at once. Its data is kept, and memory is not touched. */
304
+ switchOff(): Promise<SwitchResult>;
305
+ }
306
+
307
+ export interface MemoryControl {
308
+ /** What memory costs to run, as the person reads it ("up to 4 GB of RAM"). */
309
+ ramCost(): string;
310
+ switchOn(progress?: (line: string) => void): Promise<SwitchResult>;
311
+ /** Stop the memory engine. What it learned is kept. */
312
+ switchOff(): Promise<SwitchResult>;
313
+ }
314
+
315
+ /** Dollars spent on reviews. */
316
+ export interface SpendTotals {
317
+ today: number;
318
+ month: number;
319
+ }
320
+
321
+ export interface SpendPort {
322
+ totals(): Promise<Known<SpendTotals>>;
323
+ }
324
+
325
+ /** Every port the home reads. */
326
+ export interface HomeAdapters {
327
+ login: PiLoginPort;
328
+ github: GithubPort;
329
+ repo: RepoPort;
330
+ clock: ClockPort;
331
+ reviews: ReviewsPort;
332
+ autoReview: AutoReviewPort;
333
+ memory: MemoryPort;
334
+ spend: SpendPort;
335
+ /** Who refreshes the login and whether it expired. Absent: the home shows
336
+ * only which providers it holds. */
337
+ loginOwner?: LoginOwnerPort;
338
+ }
@@ -0,0 +1,206 @@
1
+ // A review the home runs, as the details area draws it: the plan the preview quoted, then what `qcr review status` says
2
+ // as the detached run goes, then its findings and its real cost. Pure: the
3
+ // model (src/home/model.ts) folds each status into a Run, the panel draws it.
4
+ //
5
+ // plan previewed and started; no lens has reported yet
6
+ // lenses the lenses run (each waiting, running, done or failed)
7
+ // validate the validator checks every finding against the code
8
+ // write the write-up, once the validator is done
9
+ // done the result is in: time, cost, one line per finding
10
+ // failed failed or stopped, with why; the PR is reviewable again
11
+ //
12
+ // A lens's name is its agent name without the `pass-` prefix and the tier
13
+ // suffix (the core's `lensShortName`). Severity maps P0 and P1 to high, P2
14
+ // to medium, and anything else to low.
15
+ import { lensShortName } from "@quickchatai/pi-quickreview/src/live/lensline.js";
16
+ import type { PrReview, ReviewFinding, ReviewQuote, ReviewRunStatus } from "./ports.js";
17
+ import { plural } from "./words.js";
18
+
19
+ export type Severity = "high" | "medium" | "low";
20
+
21
+ export interface Lens {
22
+ name: string;
23
+ state: "wait" | "run" | "done" | "failed";
24
+ findings: number;
25
+ tools: number;
26
+ tool?: string;
27
+ /** When it started running, ms since the epoch. */
28
+ since?: number;
29
+ /** What it is doing now, as one line (the live log's own line). */
30
+ line?: string;
31
+ }
32
+
33
+ export interface Run {
34
+ pr: number;
35
+ stage: "plan" | "lenses" | "validate" | "write" | "done" | "failed";
36
+ lenses: Lens[];
37
+ started: number;
38
+ ended?: number;
39
+ /** The quoted estimate and hard stop; null when this home did not see the
40
+ * quote (a run re-attached after a restart). */
41
+ est: number | null;
42
+ cap: number | null;
43
+ /** What it cost: null until the result says. */
44
+ spent: number | null;
45
+ /** Files in the plan, from the quote. */
46
+ files?: number;
47
+ runId?: string;
48
+ /** What the round is doing, when no lens is running. */
49
+ now?: string;
50
+ error?: string;
51
+ report?: string;
52
+ findings: { sev: Severity; where: string; text: string }[];
53
+ /** The findings as the result gave them, for the chat message. */
54
+ raw?: readonly ReviewFinding[];
55
+ /** The finished review kept for a post. */
56
+ postFile?: string;
57
+ }
58
+
59
+ export const sevOf = (severity: string): Severity =>
60
+ /^P[01]$/i.test(severity.trim()) ? "high" : /^P2$/i.test(severity.trim()) ? "medium" : "low";
61
+
62
+ export const lensName = (agent: string): string => lensShortName(agent);
63
+
64
+ const isValidator = (agent: string): boolean => lensName(agent).startsWith("validate");
65
+
66
+ /** Where a finding is: path:line, or the whole change. */
67
+ export function whereOf(f: Pick<ReviewFinding, "path" | "line">): string {
68
+ return f.path ? `${f.path}${f.line ? `:${f.line}` : ""}` : "(whole change)";
69
+ }
70
+
71
+ /** A path's last two parts: enough to know the file in a narrow column. */
72
+ export function shortWhere(where: string): string {
73
+ return where.startsWith("(") ? where : where.split("/").slice(-2).join("/");
74
+ }
75
+
76
+ /** A run that has its quote and is about to start. */
77
+ export function plannedRun(pr: number, now: number): Run {
78
+ return {
79
+ pr,
80
+ stage: "plan",
81
+ lenses: [],
82
+ started: now,
83
+ est: null,
84
+ cap: null,
85
+ spent: null,
86
+ now: "pricing the review",
87
+ findings: [],
88
+ };
89
+ }
90
+
91
+ /** The quote's plan on the run: the lenses (the validator aside), the price. */
92
+ export function quoteRun(run: Run, q: ReviewQuote): void {
93
+ run.est = q.estimateUsd;
94
+ run.cap = q.capUsd;
95
+ run.files = q.files;
96
+ run.lenses = q.lenses
97
+ .filter((l) => !isValidator(l))
98
+ .map((l) => ({ name: lensName(l), state: "wait", findings: 0, tools: 0 }));
99
+ }
100
+
101
+ /** A run the home finds already going (or over) when it opens. */
102
+ export function attachedRun(s: ReviewRunStatus): Run {
103
+ return {
104
+ pr: s.pr ?? 0,
105
+ stage: "plan",
106
+ lenses: [],
107
+ started: s.startedAt,
108
+ est: null,
109
+ cap: null,
110
+ spent: null,
111
+ runId: s.runId,
112
+ ...(s.report !== undefined ? { report: s.report } : {}),
113
+ findings: [],
114
+ };
115
+ }
116
+
117
+ const LENS_STATE: Record<string, Lens["state"]> = {
118
+ running: "run",
119
+ completed: "done",
120
+ failed: "failed",
121
+ };
122
+
123
+ /** Fold one status into the run. Returns true once the run is over. */
124
+ export function foldStatus(run: Run, s: ReviewRunStatus, now: number): boolean {
125
+ if (s.live) {
126
+ run.now = s.live.lastActivity;
127
+ for (const a of s.live.lenses) {
128
+ if (isValidator(a.agent)) {
129
+ if (a.status === "running") run.stage = "validate";
130
+ else if (a.status === "completed" || a.status === "failed") run.stage = "write";
131
+ continue;
132
+ }
133
+ const name = lensName(a.agent);
134
+ let lens = run.lenses.find((l) => l.name === name);
135
+ if (!lens) run.lenses.push((lens = { name, state: "wait", findings: 0, tools: 0 }));
136
+ lens.state = LENS_STATE[a.status] ?? "wait";
137
+ lens.tools = a.toolCount;
138
+ lens.line = a.line;
139
+ if (a.currentTool !== undefined) lens.tool = a.currentTool;
140
+ else delete lens.tool;
141
+ if (lens.state === "run") lens.since ??= now - Math.max(0, a.durationMs);
142
+ if (run.stage === "plan") run.stage = "lenses";
143
+ }
144
+ }
145
+ if (s.state === "running") return false;
146
+ run.ended = s.endedAt ?? now;
147
+ if (s.state !== "done") {
148
+ run.stage = "failed";
149
+ run.error =
150
+ s.errors.length > 0
151
+ ? s.errors.join("; ")
152
+ : s.state === "stopped"
153
+ ? "it was stopped"
154
+ : "it ended without a result";
155
+ return true;
156
+ }
157
+ const all = s.result?.findings ?? [];
158
+ run.findings = all.map((f) => ({ sev: sevOf(f.severity), where: whereOf(f), text: f.title }));
159
+ run.raw = all;
160
+ for (const l of run.lenses) l.findings = 0;
161
+ for (const f of all) {
162
+ const lens = f.lens ? run.lenses.find((l) => l.name === lensName(f.lens!)) : undefined;
163
+ if (lens) lens.findings++;
164
+ }
165
+ for (const l of run.lenses) if (l.state === "run" || l.state === "wait") l.state = "done";
166
+ run.spent = s.result?.costUsd ?? null;
167
+ if (s.result?.postFile !== undefined) run.postFile = s.result.postFile;
168
+ run.stage = "done";
169
+ return true;
170
+ }
171
+
172
+ /** A finished run as the Reviewed list holds it. */
173
+ export function runReview(run: Run): PrReview {
174
+ return {
175
+ findings: run.findings.length,
176
+ high: run.findings.filter((f) => f.sev === "high").length,
177
+ by: "you",
178
+ at: run.ended ?? run.started,
179
+ list: run.raw ?? [],
180
+ tookMs: (run.ended ?? run.started) - run.started,
181
+ costUsd: run.spent,
182
+ ...(run.report !== undefined ? { report: run.report } : {}),
183
+ };
184
+ }
185
+
186
+ /** A finished review's findings as the chat message ⏎ sends. */
187
+ export function reviewMessage(o: { pr: number; title: string; review: PrReview }): string {
188
+ const r = o.review;
189
+ const who = r.by === "auto" ? "auto-review" : "you";
190
+ if (r.list === undefined) {
191
+ const n =
192
+ r.findings === null ? "its findings are on the pull request" : plural(r.findings, "finding");
193
+ return `**#${o.pr} ${o.title}** — reviewed by ${who}; ${n}.`;
194
+ }
195
+ if (r.list.length === 0) return `**#${o.pr} ${o.title}** — reviewed by ${who}, no findings.`;
196
+ const high = r.list.filter((f) => sevOf(f.severity) === "high").length;
197
+ return [
198
+ `**#${o.pr} ${o.title}** — reviewed by ${who}: ${plural(r.list.length, "finding")}${high ? `, ${high} high` : ""}`,
199
+ "",
200
+ ...r.list.map(
201
+ (f, i) =>
202
+ `${i + 1}. **${sevOf(f.severity)}** \`${whereOf(f)}\` — ${f.title}${f.lens ? ` _(${lensName(f.lens)})_` : ""}`,
203
+ ),
204
+ ...(r.report ? ["", `Full report: \`${r.report}\``] : []),
205
+ ].join("\n");
206
+ }