@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.
- package/README.md +137 -57
- package/bin/qcr.js +1 -1
- package/config.example.toml +60 -14
- package/deploy/ansible/README.md +20 -12
- package/deploy/ansible/inventory.example.ini +1 -1
- package/deploy/collect-secrets.sh +1 -1
- package/deploy/qcr-update.sh +1 -1
- package/dist/extensions/cli/home.js +14 -0
- package/dist/extensions/cli/home.js.map +1 -0
- package/dist/extensions/cli/login-route.js +5 -0
- package/dist/extensions/cli/login-route.js.map +1 -0
- package/dist/extensions/cli/selfimprove.js +18 -0
- package/dist/extensions/cli/selfimprove.js.map +1 -0
- package/dist/extensions/home.js +350 -0
- package/dist/extensions/home.js.map +1 -0
- package/dist/extensions/login-route.js +180 -0
- package/dist/extensions/login-route.js.map +1 -0
- package/dist/extensions/onboarding.js +35 -11
- package/dist/extensions/onboarding.js.map +1 -1
- package/dist/extensions/selfimprove.js +49 -0
- package/dist/extensions/selfimprove.js.map +1 -0
- package/dist/extensions/setup-scan.js +23 -592
- package/dist/extensions/setup-scan.js.map +1 -1
- package/dist/extensions/setup.js +2 -47
- package/dist/extensions/setup.js.map +1 -1
- package/dist/src/archive/restore.js +18 -15
- package/dist/src/archive/restore.js.map +1 -1
- package/dist/src/botworker.js +13 -2
- package/dist/src/botworker.js.map +1 -1
- package/dist/src/channelfs.js +3 -26
- package/dist/src/channelfs.js.map +1 -1
- package/dist/src/ciretry.js +2 -1
- package/dist/src/ciretry.js.map +1 -1
- package/dist/src/cli.js +54 -61
- package/dist/src/cli.js.map +1 -1
- package/dist/src/cliops.js +3 -2
- package/dist/src/cliops.js.map +1 -1
- package/dist/src/commands.js +25 -2
- package/dist/src/commands.js.map +1 -1
- package/dist/src/config.js +32 -2
- package/dist/src/config.js.map +1 -1
- package/dist/src/daemon.js +50 -8
- package/dist/src/daemon.js.map +1 -1
- package/dist/src/debuground.js +1 -0
- package/dist/src/debuground.js.map +1 -1
- package/dist/src/debugroundpi.js +6 -1
- package/dist/src/debugroundpi.js.map +1 -1
- package/dist/src/dispatch.js +5 -4
- package/dist/src/dispatch.js.map +1 -1
- package/dist/src/engine/caserunner-sdk.js +15 -251
- package/dist/src/engine/caserunner-sdk.js.map +1 -1
- package/dist/src/engine/debugpi.js +17 -5
- package/dist/src/engine/debugpi.js.map +1 -1
- package/dist/src/execboundary.js +10 -3
- package/dist/src/execboundary.js.map +1 -1
- package/dist/src/github.js +51 -16
- package/dist/src/github.js.map +1 -1
- package/dist/src/githubtoken.js +346 -0
- package/dist/src/githubtoken.js.map +1 -0
- package/dist/src/home/adapters.js +349 -0
- package/dist/src/home/adapters.js.map +1 -0
- package/dist/src/home/advanced.js +318 -0
- package/dist/src/home/advanced.js.map +1 -0
- package/dist/src/home/advancedtools.js +57 -0
- package/dist/src/home/advancedtools.js.map +1 -0
- package/dist/src/home/autoreview.js +325 -0
- package/dist/src/home/autoreview.js.map +1 -0
- package/dist/src/home/daemonstatus.js +32 -0
- package/dist/src/home/daemonstatus.js.map +1 -0
- package/dist/src/home/devicelogin.js +61 -0
- package/dist/src/home/devicelogin.js.map +1 -0
- package/dist/src/home/launch.js +202 -0
- package/dist/src/home/launch.js.map +1 -0
- package/dist/src/home/loginowner.js +205 -0
- package/dist/src/home/loginowner.js.map +1 -0
- package/dist/src/home/memory.js +122 -0
- package/dist/src/home/memory.js.map +1 -0
- package/dist/src/home/model.js +811 -0
- package/dist/src/home/model.js.map +1 -0
- package/dist/src/home/panel.js +520 -0
- package/dist/src/home/panel.js.map +1 -0
- package/dist/src/home/ports.js +19 -0
- package/dist/src/home/ports.js.map +1 -0
- package/dist/src/home/review.js +163 -0
- package/dist/src/home/review.js.map +1 -0
- package/dist/src/home/reviews.js +478 -0
- package/dist/src/home/reviews.js.map +1 -0
- package/dist/src/home/setup.js +507 -0
- package/dist/src/home/setup.js.map +1 -0
- package/dist/src/home/setupadapters.js +214 -0
- package/dist/src/home/setupadapters.js.map +1 -0
- package/dist/src/home/setupcard.js +199 -0
- package/dist/src/home/setupcard.js.map +1 -0
- package/dist/src/home/setuptools.js +45 -0
- package/dist/src/home/setuptools.js.map +1 -0
- package/dist/src/home/spend.js +160 -0
- package/dist/src/home/spend.js.map +1 -0
- package/dist/src/home/switches.js +209 -0
- package/dist/src/home/switches.js.map +1 -0
- package/dist/src/home/switchon.js +439 -0
- package/dist/src/home/switchon.js.map +1 -0
- package/dist/src/home/toolnames.js +41 -0
- package/dist/src/home/toolnames.js.map +1 -0
- package/dist/src/home/tune.js +341 -0
- package/dist/src/home/tune.js.map +1 -0
- package/dist/src/home/words.js +7 -0
- package/dist/src/home/words.js.map +1 -0
- package/dist/src/homes.js +14 -0
- package/dist/src/homes.js.map +1 -1
- package/dist/src/install.js +1 -1
- package/dist/src/install.js.map +1 -1
- package/dist/src/ipc/workerspec.js +8 -0
- package/dist/src/ipc/workerspec.js.map +1 -1
- package/dist/src/live/publish.js +1 -1
- package/dist/src/live/publish.js.map +1 -1
- package/dist/src/livecli.js +1 -1
- package/dist/src/livecli.js.map +1 -1
- package/dist/src/loginhint.js +8 -3
- package/dist/src/loginhint.js.map +1 -1
- package/dist/src/loginrefresh/handover.js +121 -0
- package/dist/src/loginrefresh/handover.js.map +1 -0
- package/dist/src/loginrefresh/lock.js +54 -3
- package/dist/src/loginrefresh/lock.js.map +1 -1
- package/dist/src/loginrefresh/pirefresh.js +3 -0
- package/dist/src/loginrefresh/pirefresh.js.map +1 -1
- package/dist/src/loginrefresh/refresher.js +33 -5
- package/dist/src/loginrefresh/refresher.js.map +1 -1
- package/dist/src/loginrefresh/supervisor.js +18 -1
- package/dist/src/loginrefresh/supervisor.js.map +1 -1
- package/dist/src/npmverbs.js +46 -14
- package/dist/src/npmverbs.js.map +1 -1
- package/dist/src/onboard/choices.js +35 -4
- package/dist/src/onboard/choices.js.map +1 -1
- package/dist/src/onboard/engine.js +32 -306
- package/dist/src/onboard/engine.js.map +1 -1
- package/dist/src/onboard/pipin.js +22 -0
- package/dist/src/onboard/pipin.js.map +1 -0
- package/dist/src/onboard/stepforward.js +41 -0
- package/dist/src/onboard/stepforward.js.map +1 -0
- package/dist/src/onboard/steps/appslug.js +4 -1
- package/dist/src/onboard/steps/appslug.js.map +1 -1
- package/dist/src/onboard/steps/bringup.js +3 -2
- package/dist/src/onboard/steps/bringup.js.map +1 -1
- package/dist/src/onboard/steps/compose.js +29 -0
- package/dist/src/onboard/steps/compose.js.map +1 -1
- package/dist/src/onboard/steps/configfill.js +120 -39
- package/dist/src/onboard/steps/configfill.js.map +1 -1
- package/dist/src/onboard/steps/githubaccount.js +595 -0
- package/dist/src/onboard/steps/githubaccount.js.map +1 -0
- package/dist/src/onboard/steps/githubapp.js +65 -7
- package/dist/src/onboard/steps/githubapp.js.map +1 -1
- package/dist/src/onboard/steps/golive.js +2 -0
- package/dist/src/onboard/steps/golive.js.map +1 -1
- package/dist/src/onboard/steps/index.js +11 -0
- package/dist/src/onboard/steps/index.js.map +1 -1
- package/dist/src/onboard/steps/ingress.js +80 -25
- package/dist/src/onboard/steps/ingress.js.map +1 -1
- package/dist/src/onboard/steps/llmauth.js +103 -30
- package/dist/src/onboard/steps/llmauth.js.map +1 -1
- package/dist/src/onboard/steps/loginshare.js +213 -0
- package/dist/src/onboard/steps/loginshare.js.map +1 -0
- package/dist/src/onboard/steps/memory.js +67 -3
- package/dist/src/onboard/steps/memory.js.map +1 -1
- package/dist/src/onboard/steps/proof.js +366 -56
- package/dist/src/onboard/steps/proof.js.map +1 -1
- package/dist/src/onboard/steps/repoconfig.js +72 -0
- package/dist/src/onboard/steps/repoconfig.js.map +1 -0
- package/dist/src/onboard/steps/topology.js +6 -6
- package/dist/src/onboard/steps/topology.js.map +1 -1
- package/dist/src/onboard/steps/transport.js +9 -1
- package/dist/src/onboard/steps/transport.js.map +1 -1
- package/dist/src/onboard/steps/tuiroute.js +102 -0
- package/dist/src/onboard/steps/tuiroute.js.map +1 -0
- package/dist/src/onboard/steps/verifyup.js +17 -1
- package/dist/src/onboard/steps/verifyup.js.map +1 -1
- package/dist/src/onboard/toolnames.js +30 -0
- package/dist/src/onboard/toolnames.js.map +1 -0
- package/dist/src/operatorwrite.js +23 -0
- package/dist/src/operatorwrite.js.map +1 -0
- package/dist/src/outcomes.js +4 -1
- package/dist/src/outcomes.js.map +1 -1
- package/dist/src/piagentdir.js +13 -0
- package/dist/src/piagentdir.js.map +1 -0
- package/dist/src/pilogin.js +31 -16
- package/dist/src/pilogin.js.map +1 -1
- package/dist/src/posting-journal.js +2 -1
- package/dist/src/posting-journal.js.map +1 -1
- package/dist/src/posting-outbox.js +6 -2
- package/dist/src/posting-outbox.js.map +1 -1
- package/dist/src/posting-receipt.js +14 -1
- package/dist/src/posting-receipt.js.map +1 -1
- package/dist/src/qcrbin.js +16 -11
- package/dist/src/qcrbin.js.map +1 -1
- package/dist/src/recheck.js +2 -1
- package/dist/src/recheck.js.map +1 -1
- package/dist/src/reconcile.js +22 -2
- package/dist/src/reconcile.js.map +1 -1
- package/dist/src/reviewargs.js +122 -0
- package/dist/src/reviewargs.js.map +1 -0
- package/dist/src/reviewcli.js +7 -161
- package/dist/src/reviewcli.js.map +1 -1
- package/dist/src/reviewdetach.js +76 -11
- package/dist/src/reviewdetach.js.map +1 -1
- package/dist/src/reviewhistory.js +32 -6
- package/dist/src/reviewhistory.js.map +1 -1
- package/dist/src/reviewnow.js +45 -0
- package/dist/src/reviewnow.js.map +1 -0
- package/dist/src/scancli.js +39 -691
- package/dist/src/scancli.js.map +1 -1
- package/dist/src/selfimprove.js +66 -0
- package/dist/src/selfimprove.js.map +1 -0
- package/dist/src/setup/adapters.js +5 -223
- package/dist/src/setup/adapters.js.map +1 -1
- package/dist/src/setup/caserunner.js +15 -249
- package/dist/src/setup/caserunner.js.map +1 -1
- package/dist/src/setup/engine.js +32 -341
- package/dist/src/setup/engine.js.map +1 -1
- package/dist/src/setup/facts.js +3 -592
- package/dist/src/setup/facts.js.map +1 -1
- package/dist/src/setup/findings.js +3 -947
- package/dist/src/setup/findings.js.map +1 -1
- package/dist/src/setup/presentation.js +3 -8
- package/dist/src/setup/presentation.js.map +1 -1
- package/dist/src/setup/scan.js +3 -724
- package/dist/src/setup/scan.js.map +1 -1
- package/dist/src/setup/scanbuild.js +9 -92
- package/dist/src/setup/scanbuild.js.map +1 -1
- package/dist/src/setup/scanlease.js +3 -250
- package/dist/src/setup/scanlease.js.map +1 -1
- package/dist/src/setup/scanreport.js +3 -288
- package/dist/src/setup/scanreport.js.map +1 -1
- package/dist/src/setup/scanrun.js +3 -1732
- package/dist/src/setup/scanrun.js.map +1 -1
- package/dist/src/setup/scantree.js +3 -256
- package/dist/src/setup/scantree.js.map +1 -1
- package/dist/src/setup/stage2request.js +3 -258
- package/dist/src/setup/stage2request.js.map +1 -1
- package/dist/src/setup/unitcut.js +3 -436
- package/dist/src/setup/unitcut.js.map +1 -1
- package/dist/src/state.js +2 -0
- package/dist/src/state.js.map +1 -1
- package/dist/src/statemachine.js +4 -1
- package/dist/src/statemachine.js.map +1 -1
- package/dist/src/takeover.js +1 -0
- package/dist/src/takeover.js.map +1 -1
- package/dist/src/takeoverpi.js +15 -1
- package/dist/src/takeoverpi.js.map +1 -1
- package/dist/src/tui/app.js +49 -0
- package/dist/src/tui/app.js.map +1 -1
- package/dist/src/tui/board.js +88 -12
- package/dist/src/tui/board.js.map +1 -1
- package/dist/src/tui/cmdbar.js +4 -1
- package/dist/src/tui/cmdbar.js.map +1 -1
- package/dist/src/tui/companion.js +76 -11
- package/dist/src/tui/companion.js.map +1 -1
- package/dist/src/tui/connect.js +7 -1
- package/dist/src/tui/connect.js.map +1 -1
- package/dist/src/tui/deploytab.js +2 -2
- package/dist/src/tui/deploytab.js.map +1 -1
- package/dist/src/tui/filters.js +5 -2
- package/dist/src/tui/filters.js.map +1 -1
- package/dist/src/tui/ghread.js +61 -5
- package/dist/src/tui/ghread.js.map +1 -1
- package/dist/src/tui/index.js +109 -20
- package/dist/src/tui/index.js.map +1 -1
- package/dist/src/tui/memforward.js +39 -2
- package/dist/src/tui/memforward.js.map +1 -1
- package/dist/src/tui/memory.js +3 -16
- package/dist/src/tui/memory.js.map +1 -1
- package/dist/src/tui/memoryurl.js +22 -0
- package/dist/src/tui/memoryurl.js.map +1 -0
- package/dist/src/tui/model.js +25 -0
- package/dist/src/tui/model.js.map +1 -1
- package/dist/src/tui/prpause.js +7 -0
- package/dist/src/tui/prpause.js.map +1 -1
- package/dist/src/tui/remote.js +7 -1
- package/dist/src/tui/remote.js.map +1 -1
- package/dist/src/tui/route.js +143 -0
- package/dist/src/tui/route.js.map +1 -0
- package/dist/src/tui/setupstate.js +32 -0
- package/dist/src/tui/setupstate.js.map +1 -0
- package/dist/src/tui/sshtriage.js +102 -5
- package/dist/src/tui/sshtriage.js.map +1 -1
- package/dist/src/tui/theme.js +2 -1
- package/dist/src/tui/theme.js.map +1 -1
- package/dist/src/tui/unwedge.js +2 -12
- package/dist/src/tui/unwedge.js.map +1 -1
- package/dist/src/verdicts.js +17 -5
- package/dist/src/verdicts.js.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/src/webhook.js +12 -1
- package/dist/src/webhook.js.map +1 -1
- package/dist/src/wire.js +34 -8
- package/dist/src/wire.js.map +1 -1
- package/dist/src/workerworld.js +11 -1
- package/dist/src/workerworld.js.map +1 -1
- package/docker/README.md +1 -1
- package/docker/companion/entrypoint.sh +20 -1
- package/docker/entrypoint.sh +57 -6
- package/docker-compose.yml +16 -1
- package/extensions/cli/home.ts +14 -0
- package/extensions/cli/login-route.ts +10 -0
- package/extensions/cli/selfimprove.ts +18 -0
- package/extensions/home.ts +484 -0
- package/extensions/login-route.ts +220 -0
- package/extensions/onboarding.ts +41 -11
- package/extensions/selfimprove.ts +65 -0
- package/extensions/setup-scan.ts +79 -766
- package/extensions/setup.ts +14 -70
- package/package.json +6 -4
- package/prompts/onboarding.md +58 -18
- package/schemas/review-result.v1.json +60 -0
- package/scripts/deploy.sh +8 -6
- package/scripts/mint-token.sh +25 -4
- package/scripts/qcr-host.sh +28 -5
- package/scripts/vm-ghcr-login.sh +7 -4
- package/src/archive/restore.ts +18 -21
- package/src/botworker.ts +13 -2
- package/src/channelfs.ts +3 -26
- package/src/ciretry.ts +2 -1
- package/src/cli.ts +59 -67
- package/src/cliops.ts +3 -2
- package/src/commands.ts +28 -2
- package/src/config.ts +62 -4
- package/src/daemon.ts +58 -7
- package/src/debuground.ts +3 -0
- package/src/debugroundpi.ts +12 -1
- package/src/dispatch.ts +5 -4
- package/src/engine/caserunner-sdk.ts +29 -314
- package/src/engine/debugpi.ts +17 -5
- package/src/execboundary.ts +16 -4
- package/src/github.ts +57 -15
- package/src/githubtoken.ts +435 -0
- package/src/home/adapters.ts +418 -0
- package/src/home/advanced.ts +421 -0
- package/src/home/advancedtools.ts +96 -0
- package/src/home/autoreview.ts +385 -0
- package/src/home/daemonstatus.ts +55 -0
- package/src/home/devicelogin.ts +107 -0
- package/src/home/launch.ts +257 -0
- package/src/home/loginowner.ts +248 -0
- package/src/home/memory.ts +176 -0
- package/src/home/model.ts +965 -0
- package/src/home/panel.ts +666 -0
- package/src/home/ports.ts +338 -0
- package/src/home/review.ts +206 -0
- package/src/home/reviews.ts +565 -0
- package/src/home/setup.ts +689 -0
- package/src/home/setupadapters.ts +217 -0
- package/src/home/setupcard.ts +288 -0
- package/src/home/setuptools.ts +57 -0
- package/src/home/spend.ts +194 -0
- package/src/home/switches.ts +293 -0
- package/src/home/switchon.ts +554 -0
- package/src/home/toolnames.ts +46 -0
- package/src/home/tune.ts +405 -0
- package/src/home/words.ts +8 -0
- package/src/homes.ts +17 -0
- package/src/install.ts +1 -1
- package/src/ipc/workerspec.ts +15 -0
- package/src/live/publish.ts +4 -1
- package/src/livecli.ts +6 -1
- package/src/loginhint.ts +8 -3
- package/src/loginrefresh/handover.ts +138 -0
- package/src/loginrefresh/lock.ts +72 -3
- package/src/loginrefresh/pirefresh.ts +3 -0
- package/src/loginrefresh/refresher.ts +34 -5
- package/src/loginrefresh/supervisor.ts +25 -2
- package/src/npmverbs.ts +55 -13
- package/src/onboard/choices.ts +40 -4
- package/src/onboard/engine.ts +70 -421
- package/src/onboard/pipin.ts +31 -0
- package/src/onboard/stepforward.ts +61 -0
- package/src/onboard/steps/appslug.ts +4 -1
- package/src/onboard/steps/bringup.ts +3 -2
- package/src/onboard/steps/compose.ts +31 -0
- package/src/onboard/steps/configfill.ts +144 -40
- package/src/onboard/steps/githubaccount.ts +716 -0
- package/src/onboard/steps/githubapp.ts +92 -8
- package/src/onboard/steps/golive.ts +2 -0
- package/src/onboard/steps/index.ts +11 -0
- package/src/onboard/steps/ingress.ts +98 -31
- package/src/onboard/steps/llmauth.ts +114 -29
- package/src/onboard/steps/loginshare.ts +258 -0
- package/src/onboard/steps/memory.ts +76 -3
- package/src/onboard/steps/proof.ts +473 -55
- package/src/onboard/steps/repoconfig.ts +85 -0
- package/src/onboard/steps/topology.ts +7 -6
- package/src/onboard/steps/transport.ts +15 -0
- package/src/onboard/steps/tuiroute.ts +119 -0
- package/src/onboard/steps/verifyup.ts +20 -1
- package/src/onboard/toolnames.ts +34 -0
- package/src/operatorwrite.ts +25 -0
- package/src/outcomes.ts +8 -1
- package/src/piagentdir.ts +12 -0
- package/src/pilogin.ts +32 -16
- package/src/posting-journal.ts +6 -1
- package/src/posting-outbox.ts +10 -2
- package/src/posting-receipt.ts +17 -0
- package/src/qcrbin.ts +16 -11
- package/src/recheck.ts +2 -1
- package/src/reconcile.ts +29 -3
- package/src/reviewargs.ts +119 -0
- package/src/reviewcli.ts +6 -167
- package/src/reviewdetach.ts +107 -13
- package/src/reviewhistory.ts +20 -6
- package/src/reviewnow.ts +76 -0
- package/src/scancli.ts +75 -826
- package/src/selfimprove.ts +90 -0
- package/src/setup/adapters.ts +13 -221
- package/src/setup/caserunner.ts +34 -273
- package/src/setup/engine.ts +62 -496
- package/src/setup/facts.ts +3 -627
- package/src/setup/findings.ts +3 -1264
- package/src/setup/presentation.ts +3 -18
- package/src/setup/scan.ts +3 -1033
- package/src/setup/scanbuild.ts +20 -114
- package/src/setup/scanlease.ts +3 -297
- package/src/setup/scanreport.ts +3 -373
- package/src/setup/scanrun.ts +3 -2268
- package/src/setup/scantree.ts +3 -259
- package/src/setup/stage2request.ts +3 -347
- package/src/setup/unitcut.ts +3 -523
- package/src/state.ts +43 -0
- package/src/statemachine.ts +4 -1
- package/src/takeover.ts +5 -0
- package/src/takeoverpi.ts +16 -2
- package/src/tui/app.ts +47 -0
- package/src/tui/board.ts +111 -14
- package/src/tui/cmdbar.ts +4 -1
- package/src/tui/companion.ts +80 -11
- package/src/tui/connect.ts +7 -1
- package/src/tui/deploytab.ts +2 -2
- package/src/tui/filters.ts +7 -3
- package/src/tui/ghread.ts +74 -7
- package/src/tui/index.ts +117 -23
- package/src/tui/memforward.ts +52 -3
- package/src/tui/memory.ts +3 -15
- package/src/tui/memoryurl.ts +22 -0
- package/src/tui/model.ts +36 -2
- package/src/tui/prpause.ts +11 -2
- package/src/tui/remote.ts +9 -1
- package/src/tui/route.ts +173 -0
- package/src/tui/setupstate.ts +56 -0
- package/src/tui/sshtriage.ts +127 -6
- package/src/tui/theme.ts +2 -1
- package/src/tui/unwedge.ts +2 -14
- package/src/verdicts.ts +23 -5
- package/src/version.ts +1 -1
- package/src/webhook.ts +10 -1
- package/src/wire.ts +42 -9
- package/src/workerworld.ts +16 -2
- package/dist/src/live/projection.js +0 -450
- package/dist/src/live/projection.js.map +0 -1
- package/dist/src/live/read.js +0 -60
- package/dist/src/live/read.js.map +0 -1
- package/dist/src/onboard/launch.js +0 -83
- package/dist/src/onboard/launch.js.map +0 -1
- package/dist/src/setup/ledger.js +0 -207
- package/dist/src/setup/ledger.js.map +0 -1
- package/dist/src/setup/stage2.js +0 -617
- package/dist/src/setup/stage2.js.map +0 -1
- package/dist/src/setup/textsniff.js +0 -89
- package/dist/src/setup/textsniff.js.map +0 -1
- package/src/live/projection.ts +0 -491
- package/src/live/read.ts +0 -86
- package/src/onboard/launch.ts +0 -115
- package/src/setup/ledger.ts +0 -324
- package/src/setup/stage2.ts +0 -926
- package/src/setup/textsniff.ts +0 -95
package/extensions/setup.ts
CHANGED
|
@@ -57,7 +57,12 @@ import {
|
|
|
57
57
|
} from "@quickchatai/pi-quickreview/extensions/pi-tool.js";
|
|
58
58
|
import { fileURLToPath } from "node:url";
|
|
59
59
|
import { configHome, stateHome } from "../src/install.js";
|
|
60
|
-
import { SetupEngine
|
|
60
|
+
import { SetupEngine } from "../src/setup/engine.js";
|
|
61
|
+
import {
|
|
62
|
+
renderCut,
|
|
63
|
+
renderDraft,
|
|
64
|
+
renderStatus,
|
|
65
|
+
} from "@quickchatai/pi-quickreview/src/scan/cutrender.js";
|
|
61
66
|
import type { HistoryTheme, HistoryThemesFile } from "../src/setup/history.js";
|
|
62
67
|
import {
|
|
63
68
|
HISTORY_SECTIONS,
|
|
@@ -154,75 +159,14 @@ export function renderFacts(facts: RepoFacts, head: string | null): string {
|
|
|
154
159
|
].join("\n\n");
|
|
155
160
|
}
|
|
156
161
|
|
|
157
|
-
export
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const over = u.cases?.some((c) => c.over_budget)
|
|
166
|
-
? " [a file alone exceeds one case — a scan reads it in line ranges]"
|
|
167
|
-
: "";
|
|
168
|
-
return ` - ${u.name} [${u.kind}] ${u.roots.map(displayRoot).join(", ")}: ${u.files ?? "UNKNOWN"} files, ${u.reviewable ?? "UNKNOWN"} reviewable, ${u.lines ?? "UNKNOWN"} lines${split}${over}${u.note ? ` — ${u.note}` : ""}`;
|
|
169
|
-
});
|
|
170
|
-
const lines = [`${title}:`, ...rows];
|
|
171
|
-
if (v.ignored.length > 0)
|
|
172
|
-
lines.push(` ignored: ${v.ignored.join(", ")} (${v.ignored_files ?? "UNKNOWN"} files)`);
|
|
173
|
-
for (const e of v.errors) lines.push(` ✗ ${e}`);
|
|
174
|
-
for (const b of v.blocking_save) lines.push(` ! ${b}`);
|
|
175
|
-
return lines.join("\n");
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/** How a rendering names the save that makes a draft the cut — the tool, or
|
|
179
|
-
* the `qcr scan units` verb. */
|
|
180
|
-
export interface CutVerbs {
|
|
181
|
-
save: string;
|
|
182
|
-
}
|
|
183
|
-
export const CUT_TOOL_VERBS: CutVerbs = { save: "setup_unit_cut_save" };
|
|
184
|
-
export const CUT_CLI_VERBS: CutVerbs = { save: "qcr scan units save" };
|
|
185
|
-
|
|
186
|
-
/** A stored or adjusted draft, and that it is not in use until saved. */
|
|
187
|
-
export function renderDraft(
|
|
188
|
-
title: string,
|
|
189
|
-
draft: CutView,
|
|
190
|
-
verbs: CutVerbs = CUT_TOOL_VERBS,
|
|
191
|
-
): string {
|
|
192
|
-
return `${renderCut(title, draft)}\n\nNot in use until ${verbs.save}.`;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
export function renderStatus(s: CutStatus): string {
|
|
196
|
-
const out: string[] = [];
|
|
197
|
-
for (const p of s.problems) out.push(`✗ ${p}`);
|
|
198
|
-
if (s.saved) {
|
|
199
|
-
const stale =
|
|
200
|
-
s.saved.blocking_save.length > 0 ? " — STALE against the repo now, see the ! lines" : "";
|
|
201
|
-
out.push(
|
|
202
|
-
renderCut(
|
|
203
|
-
`Saved unit cut (saved ${s.saved.saved_at}${s.saved.head ? ` at ${s.saved.head.slice(0, 12)}` : ""})${stale}`,
|
|
204
|
-
s.saved,
|
|
205
|
-
),
|
|
206
|
-
);
|
|
207
|
-
} else if (s.cut_file_unreadable) {
|
|
208
|
-
out.push(
|
|
209
|
-
"Saved unit cut: UNKNOWN — the cut file could not be read (see above); nothing will overwrite it.",
|
|
210
|
-
);
|
|
211
|
-
} else {
|
|
212
|
-
out.push("No saved unit cut yet.");
|
|
213
|
-
}
|
|
214
|
-
if (s.draft)
|
|
215
|
-
out.push(
|
|
216
|
-
renderCut(
|
|
217
|
-
`Draft (${s.draft.source}, updated ${s.draft.updated_at}) — not in use until saved`,
|
|
218
|
-
s.draft,
|
|
219
|
-
),
|
|
220
|
-
);
|
|
221
|
-
if (s.has_previous)
|
|
222
|
-
out.push("The cut before the saved one is kept as `previous` in the state home.");
|
|
223
|
-
return out.join("\n\n");
|
|
224
|
-
}
|
|
225
|
-
|
|
162
|
+
export {
|
|
163
|
+
CUT_CLI_VERBS,
|
|
164
|
+
CUT_TOOL_VERBS,
|
|
165
|
+
renderCut,
|
|
166
|
+
renderDraft,
|
|
167
|
+
renderStatus,
|
|
168
|
+
type CutVerbs,
|
|
169
|
+
} from "@quickchatai/pi-quickreview/src/scan/cutrender.js";
|
|
226
170
|
export function renderThemes(themes: readonly HistoryTheme[]): string {
|
|
227
171
|
return themes.length === 0
|
|
228
172
|
? " (none — an empty history has no themes)"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quickchatai/quickreview",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"//private": "The root is the published `qcr` CLI: the whole app (TUI, daemon, companion, every verb), installed with npm, pnpm or bun. It depends on the pi plugin (packages/pi-plugin) at its exact version and on pi at the exact pins below. Publishing is a release step of its own, never part of a build.",
|
|
6
6
|
"description": "A 24/7 AI code reviewer for GitHub: a deterministic daemon driving pi review sessions, with an operator TUI and a local qcr review",
|
|
@@ -94,11 +94,10 @@
|
|
|
94
94
|
"prepack": "npm run build",
|
|
95
95
|
"watch": "node scripts/tsc-watch.mjs -b --watch --preserveWatchOutput",
|
|
96
96
|
"dev": "bash scripts/dev-tui.sh",
|
|
97
|
-
"onboard": "bash scripts/qcr onboard",
|
|
98
97
|
"test": "vitest run",
|
|
99
98
|
"//canary:pi": "The offline pi canaries (tests/pi-canary/): the real pi SDK at the pinned version on pi-ai's faux provider, so no network and no cost. They also run inside `npm test`; this is the named entry point CI requires whenever the pi dependencies change (a bump is gated by it).",
|
|
100
99
|
"canary:pi": "vitest run tests/pi-canary",
|
|
101
|
-
"//canary:pi:range": "The same canaries on each pi version the plugin's peer range (packages/pi-plugin/package.json) should hold, refusing one outside it: no argument runs the installed pi; `-- --install 1.4.x` fetches another first (the registry
|
|
100
|
+
"//canary:pi:range": "The same canaries on each pi version the plugin's peer range (packages/pi-plugin/package.json) should hold, refusing one outside it: no argument runs the installed pi; `-- --install 1.4.x` fetches another first (the registry). Run it by hand before a version joins the peer range; CI runs only the installed pi's canaries. Needs the build.",
|
|
102
101
|
"canary:pi:range": "node scripts/pi-canary-range.mjs",
|
|
103
102
|
"//lint": "Deliberately NOT chained into `test` or `build`: scripts/dev-tui.sh blocks on the build before the TUI paints (ruling 5), and an ESLint pass there is seconds of blank terminal. CI runs it as its own step.",
|
|
104
103
|
"lint": "node --max-old-space-size=4096 node_modules/eslint/bin/eslint.js .",
|
|
@@ -116,7 +115,7 @@
|
|
|
116
115
|
},
|
|
117
116
|
"dependencies": {
|
|
118
117
|
"@earendil-works/pi-ai": "1.4.0",
|
|
119
|
-
"@quickchatai/pi-quickreview": "1.1
|
|
118
|
+
"@quickchatai/pi-quickreview": "1.3.1",
|
|
120
119
|
"@earendil-works/pi-coding-agent": "1.4.0",
|
|
121
120
|
"better-sqlite3": "13.0.3",
|
|
122
121
|
"smol-toml": "1.9.1"
|
|
@@ -132,6 +131,9 @@
|
|
|
132
131
|
"vitest": "5.0.5",
|
|
133
132
|
"yaml": "2.9.1"
|
|
134
133
|
},
|
|
134
|
+
"overrides": {
|
|
135
|
+
"undici": "8.12.2"
|
|
136
|
+
},
|
|
135
137
|
"qcrPi": {
|
|
136
138
|
"//": "Named qcrPi, never `pi`: pi reads a package.json `pi` key as a package manifest, and this root is not a pi package (the plugin is packages/pi-plugin). pi and pi-ai are exact dependencies above (types for the extensions, and the VM boot's plain `npm ci` installs them beside the global CLI the image carries). This block is the mirror a bare checkout without config.toml reads: package and version must equal the dependencies, the lockfile, config.toml [pi], ansible group_vars and every Dockerfile ARG (tests/fences.test.ts [T12], tests/docker-daemon.test.ts). Lens sessions run through our own lens tools (src/engine/lens/), not a pi subagent extension, so no extra extension pin exists.",
|
|
137
139
|
"package": "@earendil-works/pi-coding-agent",
|
package/prompts/onboarding.md
CHANGED
|
@@ -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
|
-
##
|
|
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
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
|
65
|
-
whole checklist one last time and,
|
|
66
|
-
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
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
|
},
|
package/scripts/deploy.sh
CHANGED
|
@@ -46,9 +46,10 @@
|
|
|
46
46
|
# cloudflared when the inventory enables it), the
|
|
47
47
|
# containers, the image stamp, the pi settings and the
|
|
48
48
|
# reviewer stub, and the state/status.json heartbeat the
|
|
49
|
-
# status collector reads. It also warns 14 days before
|
|
50
|
-
#
|
|
51
|
-
# scripts/vm-ghcr-login.sh recorded
|
|
49
|
+
# status collector reads. It also warns 14 days before a
|
|
50
|
+
# private mirror's ghcr pull token expires (the expiry
|
|
51
|
+
# that scripts/vm-ghcr-login.sh recorded; the public
|
|
52
|
+
# release images need no login, so no record).
|
|
52
53
|
#
|
|
53
54
|
# `sync`, `dev` and `rebuild` are gone (the on-VM rsync and build are deleted):
|
|
54
55
|
# they refuse with a pointer to `release`. A pre-release fix is a release.
|
|
@@ -1083,8 +1084,9 @@ release_problem() {
|
|
|
1083
1084
|
fi
|
|
1084
1085
|
}
|
|
1085
1086
|
|
|
1086
|
-
# The
|
|
1087
|
-
#
|
|
1087
|
+
# The release images are public and pull with no login. A private mirror's
|
|
1088
|
+
# ghcr pull token expires (1 year, by ruling), and a lapsed one fails the
|
|
1089
|
+
# updater's pull. scripts/vm-ghcr-login.sh records the expiry on this
|
|
1088
1090
|
# controller; release and verify read it back. Within GHCR_WARN_DAYS of it
|
|
1089
1091
|
# (or past it) the plan line starts with WARNING. Warn only, never a refusal.
|
|
1090
1092
|
GHCR_WARN_DAYS=14
|
|
@@ -1095,7 +1097,7 @@ ghcr_expiry_status() {
|
|
|
1095
1097
|
local file iso epoch now days
|
|
1096
1098
|
file="$(qcr_ghcr_expiry_file 2>/dev/null)" || file=""
|
|
1097
1099
|
if [[ -z "$file" || ! -s "$file" ]]; then
|
|
1098
|
-
GHCR_EXPIRY_LINE="no
|
|
1100
|
+
GHCR_EXPIRY_LINE="no ghcr login recorded: the release images are public and pull without one (a private mirror logs the VM in with scripts/vm-ghcr-login.sh, which records its expiry)"
|
|
1099
1101
|
return 0
|
|
1100
1102
|
fi
|
|
1101
1103
|
iso="$(head -1 "$file" | tr -d '[:space:]')"
|
package/scripts/mint-token.sh
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# mint-token.sh —
|
|
2
|
+
# mint-token.sh — the daemon's GitHub token for the pi sessions' `gh` prefixing
|
|
3
|
+
# and the git credential helper.
|
|
3
4
|
#
|
|
4
|
-
#
|
|
5
|
+
# Under `[github] auth = "user"` (the person's own credential, polling-only;
|
|
6
|
+
# SECURITY.md) it prints the token file `<secrets dir>/github_token`
|
|
7
|
+
# that the host-side refresher (`qcr github-token sync`) keeps fresh, and does
|
|
8
|
+
# nothing else: no App, no JWT, no cache. --refresh re-reads the same file.
|
|
9
|
+
#
|
|
10
|
+
# Otherwise (`auth = "app"`, the default) it is the shell equivalent of
|
|
11
|
+
# packages/pi-plugin/src/githubAuth.ts:
|
|
5
12
|
# * RS256 app JWT, iat = now-60s, exp = iat+9min (≤10 min ceiling)
|
|
6
13
|
# * installation id resolved via GET /app/installations
|
|
7
14
|
# * POST /app/installations/{id}/access_tokens for the installation token
|
|
8
15
|
# * token + expires_at cached; reused while (expires_at - now) > 5 min
|
|
9
16
|
# * single-flight via an mkdir lock; --refresh re-mints (the 401 path)
|
|
10
17
|
#
|
|
11
|
-
# The app PEM is the only credential
|
|
12
|
-
# Prints the bare token to stdout. stdlib tools only: bash, openssl, curl, python3.
|
|
18
|
+
# The app PEM is the App route's only credential. Prints the bare token to stdout. stdlib tools only: bash, openssl, curl, python3.
|
|
13
19
|
#
|
|
14
20
|
# Usage: mint-token.sh [--refresh]
|
|
15
21
|
# e.g. GH_TOKEN="$(scripts/mint-token.sh)" gh pr view 123
|
|
@@ -63,6 +69,21 @@ cfg_sed() { # crude fallback: first `key = "value"` inside [section]
|
|
|
63
69
|
# ~/.config/quickreview-bot). The same answer the daemon's loader reaches.
|
|
64
70
|
SECRETS_DIR="$(qcr_locate_secrets "$(cfg github secrets_dir || true)")" || exit 1
|
|
65
71
|
|
|
72
|
+
# ---- auth = "user": the person's token file, as written ---------------------
|
|
73
|
+
|
|
74
|
+
AUTH="$(cfg github auth 2>/dev/null || true)"
|
|
75
|
+
AUTH="${AUTH:-app}"
|
|
76
|
+
if [[ "$AUTH" == "user" ]]; then
|
|
77
|
+
TOKEN_FILE="$SECRETS_DIR/github_token"
|
|
78
|
+
[[ -r "$TOKEN_FILE" ]] ||
|
|
79
|
+
die "unreadable user token: $TOKEN_FILE ([github] auth = \"user\"; run \`qcr github-token sync\` on the host)"
|
|
80
|
+
token="$(tr -d '[:space:]' < "$TOKEN_FILE")"
|
|
81
|
+
[[ -n "$token" ]] || die "empty user token file: $TOKEN_FILE (run \`qcr github-token sync\` on the host)"
|
|
82
|
+
printf '%s\n' "$token"
|
|
83
|
+
exit 0
|
|
84
|
+
fi
|
|
85
|
+
[[ "$AUTH" == "app" ]] || die "[github] auth must be \"app\" or \"user\" (got \"$AUTH\")"
|
|
86
|
+
|
|
66
87
|
APP_ID_FILE="$SECRETS_DIR/app_id"
|
|
67
88
|
PEM_FILE="$SECRETS_DIR/app.pem"
|
|
68
89
|
[[ -r "$APP_ID_FILE" ]] || die "unreadable app id: $APP_ID_FILE"
|
package/scripts/qcr-host.sh
CHANGED
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
# `stop` find it by label. `stop` sends `docker stop -t
|
|
13
13
|
# <grace>`, then `docker kill`: the container is the
|
|
14
14
|
# hard-kill backstop for a driver whose loop is frozen.
|
|
15
|
-
# qcr a bare qcr opens the
|
|
15
|
+
# qcr a bare qcr (or `qcr home`) opens the home: the image's
|
|
16
|
+
# pi with the plugin and its panel (home mode)
|
|
17
|
+
# qcr tui the operator TUI (tui mode), the one verb that starts
|
|
18
|
+
# the companion
|
|
16
19
|
# qcr login [provider] pi's own /login, stored in the qcr-login volume
|
|
17
20
|
# qcr update [version] pull a newer image and repin this file
|
|
18
21
|
#
|
|
@@ -21,8 +24,8 @@
|
|
|
21
24
|
# a worktree's common git dir at its own path read-only
|
|
22
25
|
# the qcr-state volume /opt/qcr/state read-write
|
|
23
26
|
# the qcr-login volume /qcr-login read-only
|
|
24
|
-
# (only `login`
|
|
25
|
-
# at pi's agent dir; its files are in
|
|
27
|
+
# (only `login` and the home mount it
|
|
28
|
+
# read-write, at pi's agent dir; its files are in
|
|
26
29
|
# group 4747, which every call joins,
|
|
27
30
|
# so a uid change never loses the login)
|
|
28
31
|
# ~/.config/qcr/profiles /qcr-config/profiles read-only
|
|
@@ -219,11 +222,20 @@ split=1
|
|
|
219
222
|
drop=0
|
|
220
223
|
gh=1
|
|
221
224
|
case "$verb" in
|
|
225
|
+
# The home is the person's own pi, as `qcr` from npm opens it: pi's agent
|
|
226
|
+
# dir on the login volume, read-write (its device login lands there), its
|
|
227
|
+
# config and sessions on the state volume, and the GitHub token for its `gh`.
|
|
222
228
|
'')
|
|
223
|
-
mode=
|
|
229
|
+
mode=home
|
|
224
230
|
tty=1
|
|
225
231
|
split=0
|
|
226
232
|
;;
|
|
233
|
+
home)
|
|
234
|
+
mode=home
|
|
235
|
+
tty=1
|
|
236
|
+
split=0
|
|
237
|
+
drop=1
|
|
238
|
+
;;
|
|
227
239
|
tui)
|
|
228
240
|
mode=tui
|
|
229
241
|
tty=1
|
|
@@ -555,7 +567,8 @@ fi
|
|
|
555
567
|
# ---- the GitHub token (GITHUB_TOKEN, GH_TOKEN, gh; no App on a laptop) -----
|
|
556
568
|
|
|
557
569
|
# The claim call only reads git: it needs no token, and a token file is read once.
|
|
558
|
-
|
|
570
|
+
# The home is handed it too: its `gh` lists and opens the pull requests.
|
|
571
|
+
if { [ "$split" = 1 ] || [ "$mode" = home ]; } && [ "$gh" = 1 ] && [ "$phase" != claim ]; then
|
|
559
572
|
token="${GITHUB_TOKEN:-}"
|
|
560
573
|
[ -n "$token" ] || token="${GH_TOKEN:-}"
|
|
561
574
|
if [ -z "$token" ] && command -v gh >/dev/null 2>&1; then
|
|
@@ -603,6 +616,16 @@ if [ "$mode" = login ]; then
|
|
|
603
616
|
# pi's own /login, written to the login volume: the only read-write mount of
|
|
604
617
|
# it. A login needs no repo, no state and no profiles.
|
|
605
618
|
set -- "$@" --mount "type=volume,src=qcr-login,dst=/home/qcr/.pi/agent"
|
|
619
|
+
elif [ "$mode" = home ]; then
|
|
620
|
+
# The home works on a GitHub repository, not on the directory you stand in:
|
|
621
|
+
# no repo mount. pi's agent dir is the login volume, read-write, as login's
|
|
622
|
+
# is. Its state home, sessions and config.toml (the repository it picks,
|
|
623
|
+
# which it writes) live on the state volume, so they persist and stay
|
|
624
|
+
# writable; the install home is never mounted.
|
|
625
|
+
set -- "$@" --mount "type=volume,src=qcr-login,dst=/home/qcr/.pi/agent"
|
|
626
|
+
set -- "$@" --mount "type=volume,src=qcr-state,dst=/opt/qcr/state"
|
|
627
|
+
set -- "$@" -e QCR_STATE_HOME=/opt/qcr/state/home
|
|
628
|
+
set -- "$@" -e QCR_CONFIG=/opt/qcr/state/home/config.toml
|
|
606
629
|
else
|
|
607
630
|
# The repo, read-only; a worktree's common git dir at its own path.
|
|
608
631
|
set -- "$@" --mount "type=bind,src=$root,dst=/repo,readonly" -w "/repo$rel"
|
package/scripts/vm-ghcr-login.sh
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# vm-ghcr-login.sh — log the review VM in to ghcr.io, so it can pull
|
|
3
|
-
#
|
|
4
|
-
#
|
|
2
|
+
# vm-ghcr-login.sh — log the review VM in to ghcr.io, so it can pull images
|
|
3
|
+
# that are not public: a private mirror named by QC_RELEASE_IMAGE and
|
|
4
|
+
# QC_RELEASE_MEMORY_IMAGE. The release images are public and pull with no
|
|
5
|
+
# login, so a VM on them needs none of this. Run by the owner, on the
|
|
6
|
+
# controller. Idempotent: running it again replaces the login and the recorded
|
|
7
|
+
# expiry.
|
|
5
8
|
#
|
|
6
9
|
# The credential is a CLASSIC personal access token, scoped read:packages and
|
|
7
10
|
# nothing else (the one carve-out from the App-only credential rule, for the
|
|
@@ -26,7 +29,7 @@
|
|
|
26
29
|
# scripts/vm-ghcr-login.sh --version X.Y.Z [--vm HOST] [--login USER] [--token-file FILE]
|
|
27
30
|
# pbpaste | scripts/vm-ghcr-login.sh --version X.Y.Z # token on stdin
|
|
28
31
|
#
|
|
29
|
-
# --version a published
|
|
32
|
+
# --version a published version; both images must exist at it
|
|
30
33
|
# --vm ssh target (default: $QC_VM_HOST, else the inventory's first host)
|
|
31
34
|
# --login the GitHub login to store (default: the token's own; if given
|
|
32
35
|
# it must be the token's)
|
package/src/archive/restore.ts
CHANGED
|
@@ -32,13 +32,7 @@ import { readdir } from "node:fs/promises";
|
|
|
32
32
|
import { join, relative } from "node:path";
|
|
33
33
|
import type { StateStore } from "../state.js";
|
|
34
34
|
import { yieldToLoop } from "@quickchatai/pi-quickreview/src/yieldloop.js";
|
|
35
|
-
import {
|
|
36
|
-
archiveStamp,
|
|
37
|
-
bundlePassOf,
|
|
38
|
-
freshPassId,
|
|
39
|
-
identityFields,
|
|
40
|
-
sameRecorded,
|
|
41
|
-
} from "./archivewrite.js";
|
|
35
|
+
import { archiveStamp, bundlePassOf, freshPassId, identityFields } from "./archivewrite.js";
|
|
42
36
|
import { readBundleRecords } from "./bundle.js";
|
|
43
37
|
import { sameIdentity } from "./fsutil.js";
|
|
44
38
|
import {
|
|
@@ -182,20 +176,23 @@ export async function restorePr(
|
|
|
182
176
|
const steady = sameIdentity(live, after);
|
|
183
177
|
if (steady && d.bytes === r.bytes && d.sha256 === r.sha256) {
|
|
184
178
|
out.present += 1;
|
|
185
|
-
// Its identity is recorded
|
|
186
|
-
//
|
|
187
|
-
//
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
179
|
+
// Its identity is recorded, always. A file an earlier restore pass
|
|
180
|
+
// put back — one that died before its entry was written — is
|
|
181
|
+
// unknown to the manifest otherwise, and a re-archive after a
|
|
182
|
+
// re-close would compress the same bytes again under `.v2` instead
|
|
183
|
+
// of reusing the archived copy. Its identity is no sign of whether
|
|
184
|
+
// it was ever unlinked: the filesystem hands a freed inode number
|
|
185
|
+
// back, and the restore gave the file its original size and mtime,
|
|
186
|
+
// so a file put back can carry exactly the identity the archive
|
|
187
|
+
// record holds. Recording a source that was never unlinked costs
|
|
188
|
+
// one `reused` entry at the re-archive, nothing more.
|
|
189
|
+
restored.push({
|
|
190
|
+
source: r.source,
|
|
191
|
+
archive: r.archive,
|
|
192
|
+
sha256: r.sha256,
|
|
193
|
+
...identityFields(live),
|
|
194
|
+
present: true,
|
|
195
|
+
});
|
|
199
196
|
} else out.liveDiffers.push(r.source);
|
|
200
197
|
continue;
|
|
201
198
|
}
|
package/src/botworker.ts
CHANGED
|
@@ -439,7 +439,14 @@ export async function runBotWorker(args: WorkerArgs, deps: WorkerDeps): Promise<
|
|
|
439
439
|
// The login: borrowed, blanked, and checked against this worker's own cap.
|
|
440
440
|
let auth: EngineAuth;
|
|
441
441
|
try {
|
|
442
|
-
auth = engineCredentials({
|
|
442
|
+
auth = engineCredentials({
|
|
443
|
+
srcDir: spec.login_dir ?? spec.agent_dir,
|
|
444
|
+
needMs: spec.wall_clock_ms,
|
|
445
|
+
now,
|
|
446
|
+
// a shared pi home holds the person's other logins too: only the
|
|
447
|
+
// review's providers are admitted
|
|
448
|
+
...(spec.providers !== undefined ? { providers: spec.providers } : {}),
|
|
449
|
+
});
|
|
443
450
|
} catch (e) {
|
|
444
451
|
if (e instanceof AuthError) throw new Stop(EXIT.auth, e.message);
|
|
445
452
|
throw e;
|
|
@@ -461,7 +468,11 @@ export async function runBotWorker(args: WorkerArgs, deps: WorkerDeps): Promise<
|
|
|
461
468
|
ownsProcess: true,
|
|
462
469
|
homeDir: homedir(),
|
|
463
470
|
...(ids !== null && !("refused" in ids) ? { toolUid: ids } : {}),
|
|
464
|
-
fenceDirs: [
|
|
471
|
+
fenceDirs: [
|
|
472
|
+
...loginSourceDirs(env),
|
|
473
|
+
...(spec.login_dir ? [spec.login_dir] : []),
|
|
474
|
+
...credentialPaths(env, spec.env),
|
|
475
|
+
],
|
|
465
476
|
credentials: auth.credentials,
|
|
466
477
|
settings: agentDirSettings(spec.agent_dir),
|
|
467
478
|
});
|
package/src/channelfs.ts
CHANGED
|
@@ -1,26 +1,3 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
// imports (scanreport.ts, stage2request.ts) share it without reaching each
|
|
5
|
-
// other at runtime.
|
|
6
|
-
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
7
|
-
import { dirname } from "node:path";
|
|
8
|
-
|
|
9
|
-
/** A file's text, or null when it is ABSENT — any other failure throws, so a
|
|
10
|
-
* reader can tell "not written yet" from "cannot be read". */
|
|
11
|
-
export function readTextIfPresent(path: string): string | null {
|
|
12
|
-
try {
|
|
13
|
-
return readFileSync(path, "utf8");
|
|
14
|
-
} catch (err) {
|
|
15
|
-
if ((err as NodeJS.ErrnoException).code === "ENOENT") return null;
|
|
16
|
-
throw err;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** tmp+rename: a reader never sees a half-written file. */
|
|
21
|
-
export function writeAtomic(path: string, text: string): void {
|
|
22
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
23
|
-
const tmp = `${path}.${process.pid}.tmp`;
|
|
24
|
-
writeFileSync(tmp, text);
|
|
25
|
-
renameSync(tmp, path);
|
|
26
|
-
}
|
|
1
|
+
// Moved to the plugin (packages/pi-plugin/src/scan/channelfs.ts): this name
|
|
2
|
+
// stays for the app's importers.
|
|
3
|
+
export * from "@quickchatai/pi-quickreview/src/scan/channelfs.js";
|
package/src/ciretry.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// is re-queued when its CI turns green, so its session can decide again.
|
|
5
5
|
//
|
|
6
6
|
// Nothing here triggers, re-runs or cancels CI: the one CI call is a GET.
|
|
7
|
+
import { botAccountLogin } from "@quickchatai/pi-quickreview/src/identity.js";
|
|
7
8
|
import {
|
|
8
9
|
classifyCi,
|
|
9
10
|
type CheckSummary,
|
|
@@ -125,7 +126,7 @@ export async function retryWithheldApproval(
|
|
|
125
126
|
{ type: "trigger", source: "reconcile" },
|
|
126
127
|
{},
|
|
127
128
|
{
|
|
128
|
-
botLogin: cfg.github
|
|
129
|
+
botLogin: botAccountLogin(cfg.github),
|
|
129
130
|
...(deps.now ? { now: deps.now } : {}),
|
|
130
131
|
reason: "ci-green:withheld-approval-retry",
|
|
131
132
|
},
|