@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
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
// The setup checklist's real ports (src/home/setup.ts), and the one function
|
|
2
|
+
// that turns a process's environment into them: the env shim
|
|
3
|
+
// (extensions/cli/home.ts) calls `homeSetupFromEnv(process.env, VERSION)`.
|
|
4
|
+
//
|
|
5
|
+
// first-run checks the plugin's pi-version and git steps, over a
|
|
6
|
+
// PluginHost of this process (its PATH, the running pi)
|
|
7
|
+
// repository pick `gh`: the person's recently pushed repositories, the
|
|
8
|
+
// chosen one's canonical name and default branch, and the
|
|
9
|
+
// account's login and name
|
|
10
|
+
// the write the app config the home's repo port reads
|
|
11
|
+
// (locateConfig: $QCR_CONFIG, else the install home's
|
|
12
|
+
// config.toml), patched the way the onboarding config
|
|
13
|
+
// fill patches it (src/onboard/steps/configfill.ts):
|
|
14
|
+
// comment-preserving, only the keys that change, never
|
|
15
|
+
// dry_run. A fresh config starts from the shipped
|
|
16
|
+
// template, whose dry_run = true it keeps (invariant 6).
|
|
17
|
+
// timezone the machine's IANA zone, as Intl resolves it
|
|
18
|
+
//
|
|
19
|
+
// The silent defaults ride on the repository write: the base branch is the
|
|
20
|
+
// chosen repository's (always: it belongs to that repository), and the
|
|
21
|
+
// timezone and the owner's name and login fill a value only while it is
|
|
22
|
+
// empty (or the config is new), so an owner's own choice is never overwritten.
|
|
23
|
+
import { readFileSync } from "node:fs";
|
|
24
|
+
import { homedir } from "node:os";
|
|
25
|
+
import { join } from "node:path";
|
|
26
|
+
import { assetRoot } from "@quickchatai/pi-quickreview/src/assetroot.js";
|
|
27
|
+
import { nodeRunner } from "@quickchatai/pi-quickreview/src/plugin/runner.js";
|
|
28
|
+
import type { PluginHost } from "@quickchatai/pi-quickreview/src/plugin/session.js";
|
|
29
|
+
import { declaredPiRange } from "@quickchatai/pi-quickreview/src/plugin/versiongate.js";
|
|
30
|
+
import { writeAtomic } from "@quickchatai/pi-quickreview/src/setupchecklist.js";
|
|
31
|
+
import { locateConfig, stateHome } from "../homes.js";
|
|
32
|
+
import { piAgentDir } from "../piagentdir.js";
|
|
33
|
+
import { execRunner, type Runner, type RunResult } from "./adapters.js";
|
|
34
|
+
import { known, unknown, type Known } from "./ports.js";
|
|
35
|
+
import type { HomeSetupPorts, RepoPickPort, RepoWrite } from "./setup.js";
|
|
36
|
+
|
|
37
|
+
type Env = Readonly<Record<string, string | undefined>>;
|
|
38
|
+
|
|
39
|
+
const firstLine = (s: string): string => s.trim().split("\n")[0]?.trim() || "no output";
|
|
40
|
+
const message = (err: unknown): string => (err instanceof Error ? err.message : String(err));
|
|
41
|
+
|
|
42
|
+
/** gh's words for "you are not signed in". */
|
|
43
|
+
const SIGNED_OUT = /gh auth login|not logged in|authentication required|HTTP 401|bad credentials/i;
|
|
44
|
+
|
|
45
|
+
function ghWhy(r: RunResult): string {
|
|
46
|
+
if (r.missing) return "gh is not installed";
|
|
47
|
+
if (SIGNED_OUT.test(r.stderr)) return "gh is signed out: run `gh auth login`";
|
|
48
|
+
return firstLine(r.stderr);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The machine's IANA timezone, or null when Intl cannot say. */
|
|
52
|
+
export function systemTimezone(): string | null {
|
|
53
|
+
try {
|
|
54
|
+
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
55
|
+
return typeof tz === "string" && tz !== "" ? tz : null;
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** A file's text; null only when it does not exist. Any other failure
|
|
62
|
+
* throws: a config that exists and cannot be read is never "no config", or
|
|
63
|
+
* the template would be written over it. */
|
|
64
|
+
function readIfThere(path: string): string | null {
|
|
65
|
+
try {
|
|
66
|
+
return readFileSync(path, "utf8");
|
|
67
|
+
} catch (err) {
|
|
68
|
+
if ((err as NodeJS.ErrnoException | null)?.code === "ENOENT") return null;
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function repoPickPort(o: {
|
|
74
|
+
runner: Runner;
|
|
75
|
+
configPath: () => string;
|
|
76
|
+
templatePath: () => string;
|
|
77
|
+
read?: (path: string) => string | null;
|
|
78
|
+
write?: (path: string, text: string) => void;
|
|
79
|
+
}): RepoPickPort {
|
|
80
|
+
const read = o.read ?? readIfThere;
|
|
81
|
+
const write = o.write ?? writeAtomic;
|
|
82
|
+
return {
|
|
83
|
+
recent: async () => {
|
|
84
|
+
const r = await o.runner.run("gh", [
|
|
85
|
+
"repo",
|
|
86
|
+
"list",
|
|
87
|
+
"--limit",
|
|
88
|
+
"8",
|
|
89
|
+
"--json",
|
|
90
|
+
"nameWithOwner",
|
|
91
|
+
]);
|
|
92
|
+
if (r.code !== 0) return unknown(ghWhy(r));
|
|
93
|
+
try {
|
|
94
|
+
const rows = JSON.parse(r.stdout) as unknown;
|
|
95
|
+
if (!Array.isArray(rows)) return unknown("gh's answer is not a list");
|
|
96
|
+
return known(
|
|
97
|
+
rows.flatMap((x: { nameWithOwner?: unknown }) =>
|
|
98
|
+
typeof x?.nameWithOwner === "string" ? [x.nameWithOwner] : [],
|
|
99
|
+
),
|
|
100
|
+
);
|
|
101
|
+
} catch (err) {
|
|
102
|
+
return unknown(`gh's answer is not JSON: ${message(err)}`);
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
describe: async (repo) => {
|
|
106
|
+
const r = await o.runner.run("gh", [
|
|
107
|
+
"repo",
|
|
108
|
+
"view",
|
|
109
|
+
repo,
|
|
110
|
+
"--json",
|
|
111
|
+
"nameWithOwner,defaultBranchRef",
|
|
112
|
+
]);
|
|
113
|
+
if (r.code !== 0) return { ok: false, why: ghWhy(r) };
|
|
114
|
+
try {
|
|
115
|
+
const v = JSON.parse(r.stdout) as {
|
|
116
|
+
nameWithOwner?: unknown;
|
|
117
|
+
defaultBranchRef?: { name?: unknown } | null;
|
|
118
|
+
};
|
|
119
|
+
const branch = v.defaultBranchRef?.name;
|
|
120
|
+
return {
|
|
121
|
+
ok: true,
|
|
122
|
+
repo: typeof v.nameWithOwner === "string" ? v.nameWithOwner : repo,
|
|
123
|
+
defaultBranch: typeof branch === "string" && branch !== "" ? branch : null,
|
|
124
|
+
};
|
|
125
|
+
} catch (err) {
|
|
126
|
+
return { ok: false, why: `gh's answer is not JSON: ${message(err)}` };
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
profile: async (): Promise<Known<{ login: string; name: string | null }>> => {
|
|
130
|
+
const r = await o.runner.run("gh", ["api", "user"]);
|
|
131
|
+
if (r.code !== 0) return unknown(ghWhy(r));
|
|
132
|
+
try {
|
|
133
|
+
const v = JSON.parse(r.stdout) as { login?: unknown; name?: unknown };
|
|
134
|
+
if (typeof v.login !== "string") return unknown("gh's account has no login");
|
|
135
|
+
return known({
|
|
136
|
+
login: v.login,
|
|
137
|
+
name: typeof v.name === "string" && v.name.trim() !== "" ? v.name.trim() : null,
|
|
138
|
+
});
|
|
139
|
+
} catch (err) {
|
|
140
|
+
return unknown(`gh's answer is not JSON: ${message(err)}`);
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
write: async (choice): Promise<RepoWrite> => {
|
|
144
|
+
let path: string;
|
|
145
|
+
try {
|
|
146
|
+
path = o.configPath();
|
|
147
|
+
} catch (err) {
|
|
148
|
+
return { ok: false, why: message(err) };
|
|
149
|
+
}
|
|
150
|
+
let existing: string | null;
|
|
151
|
+
let template: string | null = "";
|
|
152
|
+
try {
|
|
153
|
+
existing = read(path);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
return { ok: false, why: `can't read ${path} (${message(err)}); nothing was written` };
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
if (existing === null) template = read(o.templatePath());
|
|
159
|
+
} catch {
|
|
160
|
+
template = null;
|
|
161
|
+
}
|
|
162
|
+
if (template === null)
|
|
163
|
+
return { ok: false, why: `there is no ${path} and the shipped template is not readable` };
|
|
164
|
+
// the config fill's writer, loaded only when a repository is written
|
|
165
|
+
const { renderRepoConfig } = await import("../onboard/steps/repoconfig.js");
|
|
166
|
+
const r = renderRepoConfig(existing, template, choice);
|
|
167
|
+
if (!r.ok) return r;
|
|
168
|
+
try {
|
|
169
|
+
if (r.text !== existing) write(path, r.text);
|
|
170
|
+
} catch (err) {
|
|
171
|
+
return { ok: false, why: `can't write ${path}: ${message(err)}` };
|
|
172
|
+
}
|
|
173
|
+
return { ok: true, path, wrote: r.wrote };
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** The PluginHost the first-run checks read: this process's PATH and the
|
|
179
|
+
* running pi (its version, which the env shim reads off pi). Only the
|
|
180
|
+
* plugin's pi-version and git steps run over it, so its auth answers
|
|
181
|
+
* nothing. */
|
|
182
|
+
export function firstRunHost(env: Env, piVersion: string): PluginHost {
|
|
183
|
+
return {
|
|
184
|
+
cwd: join(stateHome(env), "home"),
|
|
185
|
+
env,
|
|
186
|
+
home: (env["HOME"] ?? "").trim() || homedir(),
|
|
187
|
+
piVersion,
|
|
188
|
+
agentDir: piAgentDir(env),
|
|
189
|
+
auth: {
|
|
190
|
+
logins: () => ({}),
|
|
191
|
+
configured: () => false,
|
|
192
|
+
refresh: () => Promise.reject(new Error("the home's first-run checks hold no login")),
|
|
193
|
+
},
|
|
194
|
+
runner: nodeRunner(env),
|
|
195
|
+
shutdown: new AbortController().signal,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** The setup's options from a process's environment and the running pi's
|
|
200
|
+
* version: the env shim's one call. */
|
|
201
|
+
export function homeSetupFromEnv(env: Env, piVersion: string): HomeSetupPorts {
|
|
202
|
+
let range: string | null = null;
|
|
203
|
+
try {
|
|
204
|
+
range = declaredPiRange();
|
|
205
|
+
} catch {
|
|
206
|
+
range = null;
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
...(range !== null ? { firstRun: { host: firstRunHost(env, piVersion), range } } : {}),
|
|
210
|
+
repos: repoPickPort({
|
|
211
|
+
runner: execRunner,
|
|
212
|
+
configPath: () => locateConfig({ env }).path,
|
|
213
|
+
templatePath: () => join(assetRoot(), "config.example.toml"),
|
|
214
|
+
}),
|
|
215
|
+
timezone: systemTimezone,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
// The setup card: on a machine that is not set up, the home opens on this,
|
|
2
|
+
// centred at half the terminal's width and about half its height, instead of the panel. It draws the setup checklist
|
|
3
|
+
// (src/home/setup.ts) in pi's theme tokens; when the last step is done the
|
|
4
|
+
// extension swaps it for the panel at the top right.
|
|
5
|
+
//
|
|
6
|
+
// ╭─ quickreview ──────────────────────────── setup ─╮
|
|
7
|
+
// │ Welcome to quickreview 1 of 3 done │
|
|
8
|
+
// │ ✓ Sign in to OpenAI ChatGPT · signed in with pi │
|
|
9
|
+
// │ ▸ Connect GitHub alt+n check │ the next step
|
|
10
|
+
// │ gh is signed out: run `gh auth login` … │
|
|
11
|
+
// │ ○ Choose a repository │
|
|
12
|
+
// ├──────────────────────────────────────────────────┤
|
|
13
|
+
// │ the notice, then the key hints │
|
|
14
|
+
// ╰──────────────────────────────────────────────────╯
|
|
15
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
16
|
+
import type { Component, TuiMouseEvent, TuiMouseEventResult } from "@earendil-works/pi-tui";
|
|
17
|
+
import {
|
|
18
|
+
matchesKey,
|
|
19
|
+
truncateToWidth,
|
|
20
|
+
visibleWidth,
|
|
21
|
+
wrapTextWithAnsi,
|
|
22
|
+
} from "@earendil-works/pi-tui";
|
|
23
|
+
import type { HomeModel } from "./model.js";
|
|
24
|
+
import { loginFailureText, type HomeSetup, type SetupStepView } from "./setup.js";
|
|
25
|
+
|
|
26
|
+
type Fg = Parameters<Theme["fg"]>[0];
|
|
27
|
+
|
|
28
|
+
/** Where the card sits: centred, half the width. */
|
|
29
|
+
export const SETUP_OVERLAY = {
|
|
30
|
+
anchor: "center",
|
|
31
|
+
width: "50%",
|
|
32
|
+
minWidth: 80,
|
|
33
|
+
nonCapturing: true,
|
|
34
|
+
} as const;
|
|
35
|
+
|
|
36
|
+
/** The share of the terminal's height the card fills. */
|
|
37
|
+
export const CARD_HEIGHT = 0.5;
|
|
38
|
+
/** Sub-rows (instructions, the device code) are indented under the label. */
|
|
39
|
+
const INDENT = " ";
|
|
40
|
+
const NOTICE_ROWS = 3;
|
|
41
|
+
const SPIN = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
42
|
+
|
|
43
|
+
export interface CardHost {
|
|
44
|
+
setup: HomeSetup;
|
|
45
|
+
model: HomeModel;
|
|
46
|
+
focused(): boolean;
|
|
47
|
+
/** The terminal's height. */
|
|
48
|
+
rows(): number;
|
|
49
|
+
unfocus(): void;
|
|
50
|
+
frame(): number;
|
|
51
|
+
/** Run the next step (⏎ while the card is focused). */
|
|
52
|
+
next(): void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** What each step's key does, in the hint beside it. */
|
|
56
|
+
const VERB: Record<SetupStepView["id"], string> = {
|
|
57
|
+
login: "sign in",
|
|
58
|
+
github: "check",
|
|
59
|
+
repo: "choose",
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export class SetupCard implements Component {
|
|
63
|
+
constructor(
|
|
64
|
+
private readonly th: Theme,
|
|
65
|
+
private readonly host: CardHost,
|
|
66
|
+
) {}
|
|
67
|
+
|
|
68
|
+
private c(color: Fg, s: string): string {
|
|
69
|
+
return this.th.fg(color, s);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private spin(): string {
|
|
73
|
+
return SPIN[this.host.frame() % SPIN.length]!;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private edge(s: string): string {
|
|
77
|
+
return this.c(this.host.focused() ? "borderAccent" : "borderMuted", s);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** The key that runs the next step now. */
|
|
81
|
+
private key(): string {
|
|
82
|
+
return this.host.focused() ? "⏎" : "alt+n";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private row(w: number, left: string, right = "", selected = false): string {
|
|
86
|
+
const inner = w - 4;
|
|
87
|
+
const r = right ? ` ${right}` : "";
|
|
88
|
+
const l = truncateToWidth(left, Math.max(1, inner - visibleWidth(r)), "…");
|
|
89
|
+
const gap = Math.max(0, inner - visibleWidth(l) - visibleWidth(r));
|
|
90
|
+
let text = ` ${l}${" ".repeat(gap)}${r} `;
|
|
91
|
+
if (selected) text = this.th.bg("selectedBg", text);
|
|
92
|
+
return `${this.edge("│")}${text}${this.edge("│")}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Text under a step, wrapped inside the frame. */
|
|
96
|
+
private sub(w: number, text: string, color: Fg = "muted"): string[] {
|
|
97
|
+
const room = Math.max(10, w - 4 - INDENT.length);
|
|
98
|
+
return wrapTextWithAnsi(text, room).map((l) => this.row(w, `${INDENT}${this.c(color, l)}`));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private top(w: number): string {
|
|
102
|
+
const left = `${this.edge("╭─ ")}${this.th.bold(this.c("accent", "quickreview"))} `;
|
|
103
|
+
const right = ` ${this.c("muted", "setup")}${this.edge(" ─╮")}`;
|
|
104
|
+
const fill = Math.max(0, w - visibleWidth(left) - visibleWidth(right));
|
|
105
|
+
return `${left}${this.edge("─".repeat(fill))}${right}`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private rule(w: number): string {
|
|
109
|
+
return this.edge(`├${"─".repeat(Math.max(0, w - 2))}┤`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private bottom(w: number): string {
|
|
113
|
+
return this.edge(`╰${"─".repeat(Math.max(0, w - 2))}╯`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private stepRows(w: number, s: SetupStepView): string[] {
|
|
117
|
+
const v = this.host.setup.view();
|
|
118
|
+
const out: string[] = [];
|
|
119
|
+
const k = this.key();
|
|
120
|
+
let mark: string;
|
|
121
|
+
let label: string;
|
|
122
|
+
let right = "";
|
|
123
|
+
if (s.state === "done") {
|
|
124
|
+
mark = this.c("success", "✓");
|
|
125
|
+
label = this.c("muted", s.title);
|
|
126
|
+
right = this.c("muted", s.found ?? "done");
|
|
127
|
+
} else if (s.state === "running") {
|
|
128
|
+
mark = this.c("accent", this.spin());
|
|
129
|
+
label = this.th.bold(this.c("text", s.title));
|
|
130
|
+
right = this.c("dim", v.login.code ? "waiting for you…" : "starting…");
|
|
131
|
+
} else if (s.unknown !== undefined) {
|
|
132
|
+
mark = this.c("dim", "?");
|
|
133
|
+
label = s.next ? this.th.bold(this.c("text", s.title)) : this.c("text", s.title);
|
|
134
|
+
right = s.next
|
|
135
|
+
? `${this.c("accent", k)} ${this.c("muted", VERB[s.id])}`
|
|
136
|
+
: this.c("dim", "unknown");
|
|
137
|
+
} else if (s.next) {
|
|
138
|
+
mark = this.c("accent", "▸");
|
|
139
|
+
label = this.th.bold(this.c("text", s.title));
|
|
140
|
+
right = `${this.c("accent", k)} ${this.c("muted", VERB[s.id])}`;
|
|
141
|
+
} else {
|
|
142
|
+
mark = this.c("dim", "○");
|
|
143
|
+
label = this.c("dim", s.title);
|
|
144
|
+
}
|
|
145
|
+
out.push(this.row(w, ` ${mark} ${label}`, right, s.next));
|
|
146
|
+
if (s.state === "done") return out;
|
|
147
|
+
if (s.id === "login") out.push(...this.loginRows(w, s));
|
|
148
|
+
else if (s.unknown !== undefined)
|
|
149
|
+
out.push(...this.sub(w, `Unknown — ${s.unknown}.`, "warning"));
|
|
150
|
+
else if (s.next && s.id === "github" && s.missing)
|
|
151
|
+
out.push(...this.sub(w, `${capital(s.missing)}, then ${k} checks again.`, "warning"));
|
|
152
|
+
else if (s.next && s.id === "repo")
|
|
153
|
+
out.push(
|
|
154
|
+
...this.sub(
|
|
155
|
+
w,
|
|
156
|
+
"One of your recently pushed repositories, or paste any owner/name or GitHub URL.",
|
|
157
|
+
),
|
|
158
|
+
);
|
|
159
|
+
return out;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private loginRows(w: number, s: SetupStepView): string[] {
|
|
163
|
+
const v = this.host.setup.view();
|
|
164
|
+
const k = this.key();
|
|
165
|
+
const out: string[] = [];
|
|
166
|
+
const chatgpt = v.provider === "OpenAI";
|
|
167
|
+
const setting = "Device-code login must be on first: ChatGPT → Settings → Security.";
|
|
168
|
+
if (s.state === "running") {
|
|
169
|
+
const code = v.login.code;
|
|
170
|
+
if (!code) {
|
|
171
|
+
if (chatgpt) out.push(...this.sub(w, setting));
|
|
172
|
+
out.push(
|
|
173
|
+
this.row(
|
|
174
|
+
w,
|
|
175
|
+
`${INDENT}${this.c("accent", this.spin())} ${this.c("dim", "asking for a code…")}`,
|
|
176
|
+
),
|
|
177
|
+
);
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
out.push(this.row(w, ""));
|
|
181
|
+
out.push(
|
|
182
|
+
this.row(
|
|
183
|
+
w,
|
|
184
|
+
`${INDENT}${this.c("muted", "1 Open ")} ${this.c("accent", code.verificationUri)}`,
|
|
185
|
+
),
|
|
186
|
+
);
|
|
187
|
+
out.push(
|
|
188
|
+
this.row(
|
|
189
|
+
w,
|
|
190
|
+
`${INDENT}${this.c("muted", "2 Enter")} ${this.th.bold(this.c("text", code.userCode))}`,
|
|
191
|
+
),
|
|
192
|
+
);
|
|
193
|
+
out.push(this.row(w, ""));
|
|
194
|
+
if (chatgpt) out.push(...this.sub(w, setting, "dim"));
|
|
195
|
+
out.push(
|
|
196
|
+
this.row(
|
|
197
|
+
w,
|
|
198
|
+
`${INDENT}${this.c("accent", this.spin())} ${this.c("dim", "waiting for you to approve…")}`,
|
|
199
|
+
),
|
|
200
|
+
);
|
|
201
|
+
return out;
|
|
202
|
+
}
|
|
203
|
+
if (v.login.failure) out.push(...this.sub(w, loginFailureText(v.login.failure, k), "warning"));
|
|
204
|
+
if (s.unknown !== undefined) out.push(...this.sub(w, `Unknown — ${s.unknown}.`, "warning"));
|
|
205
|
+
if (s.next && chatgpt && v.login.failure?.kind !== "not_enabled")
|
|
206
|
+
out.push(...this.sub(w, setting));
|
|
207
|
+
return out;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private hints(w: number): string {
|
|
211
|
+
const k = (key: string, label: string): string =>
|
|
212
|
+
`${this.c("accent", key)} ${this.c("muted", label)}`;
|
|
213
|
+
return this.row(
|
|
214
|
+
w,
|
|
215
|
+
this.host.focused()
|
|
216
|
+
? `${k("⏎", "next step")} ${k("esc", "back to the chat")}`
|
|
217
|
+
: `${k("alt+n", "next step")} ${k("f2", "focus the card")} ${this.c("dim", "· or just type to ask pi")}`,
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
render(width: number): string[] {
|
|
222
|
+
const w = Math.max(40, width);
|
|
223
|
+
const v = this.host.setup.view();
|
|
224
|
+
const body = [
|
|
225
|
+
this.row(w, ""),
|
|
226
|
+
this.row(
|
|
227
|
+
w,
|
|
228
|
+
` ${this.th.bold(this.c("text", "Welcome to quickreview"))}`,
|
|
229
|
+
this.c("muted", `${v.done} of ${v.total} done `),
|
|
230
|
+
),
|
|
231
|
+
this.row(
|
|
232
|
+
w,
|
|
233
|
+
` ${this.c("muted", "Sign in once, choose a repository, and review your first pull request.")}`,
|
|
234
|
+
),
|
|
235
|
+
this.row(w, ""),
|
|
236
|
+
];
|
|
237
|
+
for (const c of v.checks) {
|
|
238
|
+
body.push(
|
|
239
|
+
this.row(
|
|
240
|
+
w,
|
|
241
|
+
` ${this.c("warning", "✗")} ${this.th.bold(this.c("text", c.title))}`,
|
|
242
|
+
c.next ? `${this.c("accent", this.key())} ${this.c("muted", "check")}` : "",
|
|
243
|
+
c.next,
|
|
244
|
+
),
|
|
245
|
+
);
|
|
246
|
+
body.push(
|
|
247
|
+
...this.sub(
|
|
248
|
+
w,
|
|
249
|
+
`${capital(c.why)}${c.next ? `, then ${this.key()} checks again.` : "."}`,
|
|
250
|
+
"warning",
|
|
251
|
+
),
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
for (const s of v.steps) body.push(...this.stepRows(w, s));
|
|
255
|
+
body.push(this.row(w, ""));
|
|
256
|
+
const foot = [this.rule(w)];
|
|
257
|
+
const n = this.host.model.notice;
|
|
258
|
+
if (n) {
|
|
259
|
+
const color: Fg = n.kind === "ok" ? "success" : n.kind === "warn" ? "warning" : "text";
|
|
260
|
+
for (const l of wrapTextWithAnsi(n.text, w - 4).slice(0, NOTICE_ROWS))
|
|
261
|
+
foot.push(this.row(w, this.c(color, l)));
|
|
262
|
+
}
|
|
263
|
+
foot.push(this.hints(w), this.bottom(w));
|
|
264
|
+
const target = Math.round(this.host.rows() * CARD_HEIGHT);
|
|
265
|
+
const spare = Math.max(0, target - 1 - body.length - foot.length);
|
|
266
|
+
const blank = (k: number): string[] => Array.from({ length: k }, () => this.row(w, ""));
|
|
267
|
+
return [
|
|
268
|
+
this.top(w),
|
|
269
|
+
...blank(Math.floor(spare / 2)),
|
|
270
|
+
...body,
|
|
271
|
+
...blank(Math.ceil(spare / 2)),
|
|
272
|
+
...foot,
|
|
273
|
+
].map((l) => truncateToWidth(l, w));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
handleInput(data: string): void {
|
|
277
|
+
if (matchesKey(data, "escape")) this.host.unfocus();
|
|
278
|
+
else if (matchesKey(data, "enter")) this.host.next();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
handleMouse(e: TuiMouseEvent): TuiMouseEventResult | undefined {
|
|
282
|
+
return e.type === "click" ? { focus: true } : undefined;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
invalidate(): void {}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const capital = (s: string): string => (s ? `${s[0]!.toUpperCase()}${s.slice(1)}` : s);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// The setup checklist's `home_*` tools: each step's action, as the model in
|
|
2
|
+
// the chat calls it. The keys call the same HomeSetup methods
|
|
3
|
+
// (extensions/home.ts), so a key and a tool never do two different things.
|
|
4
|
+
import { textResult, type QcrTool } from "@quickchatai/pi-quickreview/extensions/pi-tool.js";
|
|
5
|
+
import type { HomeSetup } from "./setup.js";
|
|
6
|
+
import type { HOME_SETUP_TOOL_NAMES } from "./toolnames.js";
|
|
7
|
+
|
|
8
|
+
export type HomeSetupToolName = (typeof HOME_SETUP_TOOL_NAMES)[number];
|
|
9
|
+
|
|
10
|
+
const NO_PARAMS = { type: "object", properties: {}, additionalProperties: false } as const;
|
|
11
|
+
|
|
12
|
+
/** One definition per HOME_SETUP_TOOL_NAMES entry. */
|
|
13
|
+
export function setupTools(setup: HomeSetup): {
|
|
14
|
+
[N in HomeSetupToolName]: QcrTool & { name: N };
|
|
15
|
+
} {
|
|
16
|
+
return {
|
|
17
|
+
home_setup_next: {
|
|
18
|
+
name: "home_setup_next",
|
|
19
|
+
label: "Home: next setup step",
|
|
20
|
+
description:
|
|
21
|
+
"Run the next step of the quickreview home's setup checklist (sign in, connect GitHub, choose a repository), as alt+n does. Answers what happened, or that setup is done.",
|
|
22
|
+
parameters: NO_PARAMS,
|
|
23
|
+
execute: async () => textResult(await setup.next()),
|
|
24
|
+
},
|
|
25
|
+
home_sign_in: {
|
|
26
|
+
name: "home_sign_in",
|
|
27
|
+
label: "Home: sign in",
|
|
28
|
+
description:
|
|
29
|
+
"Start pi's own device-code login for the provider the chat runs on. Answers with the URL and the code to enter once pi has them; the sign-in finishes in the background when the person approves it. Device-code login must be on in ChatGPT → Settings → Security.",
|
|
30
|
+
parameters: NO_PARAMS,
|
|
31
|
+
execute: async () => textResult(await setup.signIn()),
|
|
32
|
+
},
|
|
33
|
+
home_check_github: {
|
|
34
|
+
name: "home_check_github",
|
|
35
|
+
label: "Home: check GitHub",
|
|
36
|
+
description:
|
|
37
|
+
"Check again whether gh is installed and signed in. When it is not, the answer says what to run.",
|
|
38
|
+
parameters: NO_PARAMS,
|
|
39
|
+
execute: async () => textResult(await setup.checkGithub()),
|
|
40
|
+
},
|
|
41
|
+
home_choose_repo: {
|
|
42
|
+
name: "home_choose_repo",
|
|
43
|
+
label: "Home: choose a repository",
|
|
44
|
+
description:
|
|
45
|
+
"Set the repository the home reviews: owner/name or any GitHub URL of it. It is written to the qcr config's [github] repo. Without `repo`, answers the person's recently pushed repositories to choose from.",
|
|
46
|
+
parameters: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
repo: { type: "string", description: "owner/name, or a GitHub URL of the repository." },
|
|
50
|
+
},
|
|
51
|
+
additionalProperties: false,
|
|
52
|
+
},
|
|
53
|
+
execute: async (_id, p) =>
|
|
54
|
+
textResult(await setup.chooseRepo(typeof p["repo"] === "string" ? p["repo"] : undefined)),
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|