@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
|
@@ -48,7 +48,7 @@ import { createServer, type IncomingMessage, type Server, type ServerResponse }
|
|
|
48
48
|
import { isAbsolute, join } from "node:path";
|
|
49
49
|
import type { Socket } from "node:net";
|
|
50
50
|
import { mintAppJwt } from "@quickchatai/pi-quickreview/src/githubAuth.js";
|
|
51
|
-
import { CHOICE_KEYS, REPO_SLUG_RE, botLoginFor } from "../choices.js";
|
|
51
|
+
import { CHOICE_KEYS, REPO_SLUG_RE, botLoginFor, userAuthRecorded } from "../choices.js";
|
|
52
52
|
import { CONFIG_FILL_STEP_ID } from "./configfill.js";
|
|
53
53
|
import { readTomlKey, secretsDirFor } from "./ingress.js";
|
|
54
54
|
import {
|
|
@@ -416,9 +416,54 @@ export interface CallbackServerOptions {
|
|
|
416
416
|
page: (bound: { url: string; redirectUrl: string }) => string;
|
|
417
417
|
state: string;
|
|
418
418
|
/** Preferred loopback port; a busy port falls back to an ephemeral one and
|
|
419
|
-
* the manifest's redirect_url follows the port actually bound
|
|
419
|
+
* the manifest's redirect_url follows the port actually bound — except
|
|
420
|
+
* behind a `hosted` origin, where the port is strict. */
|
|
420
421
|
port: number;
|
|
421
422
|
timeoutMs: number;
|
|
423
|
+
/** A hosted setup (`QCR_ONBOARD_PUBLIC_ORIGIN`): a reverse proxy forwards
|
|
424
|
+
* this public https origin to the loopback listener on `port`. */
|
|
425
|
+
hosted?: HostedCallback;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/** The hosted callback's shape: GitHub redirects to `<origin>/manifest-callback`,
|
|
429
|
+
* the operator opens `pageUrl`, and the proxy's Host header is admitted. */
|
|
430
|
+
export interface HostedCallback {
|
|
431
|
+
/** `https://host[:port]`, no path. */
|
|
432
|
+
origin: string;
|
|
433
|
+
/** The page URL the operator is told to open (default: the origin). */
|
|
434
|
+
pageUrl: string;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/** The env knobs of a hosted setup. Total: an unusable origin is a refusal
|
|
438
|
+
* with its reason, never a silent fallback to loopback. */
|
|
439
|
+
export function hostedCallbackFromEnv(env: NodeJS.ProcessEnv): {
|
|
440
|
+
hosted?: HostedCallback;
|
|
441
|
+
problem?: string;
|
|
442
|
+
} {
|
|
443
|
+
const raw = (env["QCR_ONBOARD_PUBLIC_ORIGIN"] ?? "").trim();
|
|
444
|
+
if (raw === "") return {};
|
|
445
|
+
let u: URL;
|
|
446
|
+
try {
|
|
447
|
+
u = new URL(raw);
|
|
448
|
+
} catch {
|
|
449
|
+
return {
|
|
450
|
+
problem: `QCR_ONBOARD_PUBLIC_ORIGIN=${raw} is not a URL — set an https origin like https://<public host>`,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
if (
|
|
454
|
+
u.protocol !== "https:" ||
|
|
455
|
+
u.username ||
|
|
456
|
+
u.password ||
|
|
457
|
+
(u.pathname !== "/" && u.pathname !== "") ||
|
|
458
|
+
u.search ||
|
|
459
|
+
u.hash
|
|
460
|
+
)
|
|
461
|
+
return {
|
|
462
|
+
problem: `QCR_ONBOARD_PUBLIC_ORIGIN=${raw} must be a bare https origin (https://host[:port], no path) — GitHub redirects to <origin>${CALLBACK_PATH}`,
|
|
463
|
+
};
|
|
464
|
+
const origin = u.origin;
|
|
465
|
+
const page = (env["QCR_ONBOARD_SETUP_URL"] ?? "").trim();
|
|
466
|
+
return { hosted: { origin, pageUrl: page !== "" ? page : `${origin}/` } };
|
|
422
467
|
}
|
|
423
468
|
|
|
424
469
|
export type CallbackServerFactory = (o: CallbackServerOptions) => Promise<CallbackListener>;
|
|
@@ -516,13 +561,30 @@ export const nodeCallbackServer: CallbackServerFactory = async (o) => {
|
|
|
516
561
|
let port: number;
|
|
517
562
|
try {
|
|
518
563
|
port = await listen(o.port);
|
|
519
|
-
} catch {
|
|
564
|
+
} catch (err) {
|
|
565
|
+
// Behind a hosted origin the proxy forwards to exactly this port, so
|
|
566
|
+
// another one would be a listener nothing reaches: refuse, and say so.
|
|
567
|
+
if (o.hosted)
|
|
568
|
+
throw new Error(
|
|
569
|
+
`port ${o.port} is busy, and the hosted callback (${o.hosted.origin} → 127.0.0.1:${o.port}) needs exactly ` +
|
|
570
|
+
`that port — stop whatever holds it and run the step again (${String(err instanceof Error ? err.message : err)})`,
|
|
571
|
+
{ cause: err },
|
|
572
|
+
);
|
|
520
573
|
port = await listen(0); // preferred port busy — any loopback port will do
|
|
521
574
|
}
|
|
522
575
|
|
|
523
576
|
allowedHosts = new Set([`127.0.0.1:${port}`, `localhost:${port}`]);
|
|
524
|
-
|
|
525
|
-
|
|
577
|
+
let url = `http://127.0.0.1:${port}/`;
|
|
578
|
+
let redirectUrl = `http://127.0.0.1:${port}${CALLBACK_PATH}`;
|
|
579
|
+
if (o.hosted) {
|
|
580
|
+
// The proxy's own Host header is the public one: admitted by name, with
|
|
581
|
+
// and without the scheme's default port, alongside loopback.
|
|
582
|
+
const pub = new URL(o.hosted.origin);
|
|
583
|
+
allowedHosts.add(pub.host.toLowerCase());
|
|
584
|
+
if (pub.port === "") allowedHosts.add(`${pub.hostname.toLowerCase()}:443`);
|
|
585
|
+
url = o.hosted.pageUrl;
|
|
586
|
+
redirectUrl = `${o.hosted.origin}${CALLBACK_PATH}`;
|
|
587
|
+
}
|
|
526
588
|
html = o.page({ url, redirectUrl });
|
|
527
589
|
|
|
528
590
|
const timer = setTimeout(
|
|
@@ -720,7 +782,7 @@ export async function findInstallation(
|
|
|
720
782
|
};
|
|
721
783
|
}
|
|
722
784
|
|
|
723
|
-
async function installationToken(
|
|
785
|
+
export async function installationToken(
|
|
724
786
|
fetchFn: typeof fetch,
|
|
725
787
|
apiBase: string,
|
|
726
788
|
jwt: string,
|
|
@@ -851,6 +913,9 @@ export interface GithubAppStepOptions {
|
|
|
851
913
|
randomToken?: (bytes: number) => string;
|
|
852
914
|
/** Try to open the operator's browser at the page (best effort, never fatal). */
|
|
853
915
|
openBrowser?: boolean;
|
|
916
|
+
/** Env for the hosted-callback knobs (`QCR_ONBOARD_PUBLIC_ORIGIN`,
|
|
917
|
+
* `QCR_ONBOARD_SETUP_URL`); default the process env. */
|
|
918
|
+
env?: NodeJS.ProcessEnv;
|
|
854
919
|
}
|
|
855
920
|
|
|
856
921
|
interface Resolved {
|
|
@@ -863,8 +928,18 @@ interface Resolved {
|
|
|
863
928
|
}
|
|
864
929
|
|
|
865
930
|
function resolveLabels(ctx: StepContext): Resolved["labels"] {
|
|
866
|
-
|
|
867
|
-
|
|
931
|
+
return labelSpecs(readTextOrNull(ctx.adapters.paths.configPath), ctx.choices);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/** The three trigger/status labels this installation means — config.toml
|
|
935
|
+
* first, then the names the interview recorded, then the shipped defaults —
|
|
936
|
+
* with the colour and description the wizard creates them with. Shared with
|
|
937
|
+
* the own-account step, which creates the same labels with the person's token. */
|
|
938
|
+
export function labelSpecs(
|
|
939
|
+
config: string | null,
|
|
940
|
+
choices: Readonly<Record<string, unknown>>,
|
|
941
|
+
): Array<{ name: string; color: string; description: string }> {
|
|
942
|
+
const recorded = (choices[CHOICE_KEYS.labels] ?? {}) as Partial<
|
|
868
943
|
Record<keyof typeof DEFAULT_LABELS, unknown>
|
|
869
944
|
>;
|
|
870
945
|
return LABEL_META.map((meta) => {
|
|
@@ -1148,12 +1223,17 @@ export function githubAppStep(opts: GithubAppStepOptions = {}): OnboardingStep {
|
|
|
1148
1223
|
// The page can only be rendered once the port is known (the manifest's
|
|
1149
1224
|
// redirect_url must name the port actually bound), so the listener builds
|
|
1150
1225
|
// it from its own bound address.
|
|
1226
|
+
const hostedEnv = hostedCallbackFromEnv(opts.env ?? process.env);
|
|
1227
|
+
if (hostedEnv.problem) {
|
|
1228
|
+
return [{ name: "callback listener", ok: false, detail: hostedEnv.problem }];
|
|
1229
|
+
}
|
|
1151
1230
|
let listener: CallbackListener;
|
|
1152
1231
|
try {
|
|
1153
1232
|
listener = await serve({
|
|
1154
1233
|
state,
|
|
1155
1234
|
port: opts.callbackPort ?? DEFAULT_CALLBACK_PORT,
|
|
1156
1235
|
timeoutMs: callbackTimeoutMs,
|
|
1236
|
+
...(hostedEnv.hosted ? { hosted: hostedEnv.hosted } : {}),
|
|
1157
1237
|
page: (bound) =>
|
|
1158
1238
|
manifestPageHtml({
|
|
1159
1239
|
postUrl: appCreationUrl(target, r.githubBase),
|
|
@@ -1319,6 +1399,10 @@ export function githubAppStep(opts: GithubAppStepOptions = {}): OnboardingStep {
|
|
|
1319
1399
|
// ingress step (39), whose recorded webhook URL goes into the manifest;
|
|
1320
1400
|
// before the bring-up steps.
|
|
1321
1401
|
order: 40,
|
|
1402
|
+
// The App route only. The own-account route (github_account, order 33)
|
|
1403
|
+
// needs no App at all; an unanswered route keeps this step, so a
|
|
1404
|
+
// checklist from before the question existed still verifies its App.
|
|
1405
|
+
enabled: (choices) => !userAuthRecorded(choices),
|
|
1322
1406
|
// The reviewed repo is NOT a parameter: it is the interview's answer, read
|
|
1323
1407
|
// from the checklist (CHOICE_KEYS.repo). The only thing the operator may
|
|
1324
1408
|
// supply here is what nothing else can derive — the App's display name.
|
|
@@ -267,6 +267,8 @@ export function goLiveStep(opts: GoLiveStepOptions = {}): OnboardingStep {
|
|
|
267
267
|
'arguments to get the explanation to read out; then call it again with decision: "stay_dry_run", or with ' +
|
|
268
268
|
`decision: "go_live" AND confirm: "${GO_LIVE_CONFIRMATION}" if — and only if — they said so explicitly.`,
|
|
269
269
|
order: 78,
|
|
270
|
+
// After setup: the board offers it; finish never waits on it.
|
|
271
|
+
optional: true,
|
|
270
272
|
parameters: {
|
|
271
273
|
type: "object",
|
|
272
274
|
properties: {
|
|
@@ -7,6 +7,7 @@ import { bringUpStep } from "./bringup.js";
|
|
|
7
7
|
import { configFillStep } from "./configfill.js";
|
|
8
8
|
import { embeddingsStep } from "./embeddings.js";
|
|
9
9
|
import { escalationStep } from "./escalation.js";
|
|
10
|
+
import { githubAccountStep } from "./githubaccount.js";
|
|
10
11
|
import { githubAppStep } from "./githubapp.js";
|
|
11
12
|
import { goLiveStep } from "./golive.js";
|
|
12
13
|
import { ingressStep } from "./ingress.js";
|
|
@@ -38,6 +39,12 @@ export function defaultSteps(): OnboardingStep[] {
|
|
|
38
39
|
// ssh_preflight (22) VM only, and FIRST on that route: the alias, the
|
|
39
40
|
// agent and the passphrase trap, before anything is
|
|
40
41
|
// minted, written or deployed;
|
|
42
|
+
//
|
|
43
|
+
// The GitHub route split is the second question, asked by github_account
|
|
44
|
+
// (33): "user" (the person's own account — token file, polling, no App) or
|
|
45
|
+
// "app". Once answered, exactly one of github_account (33) / github_app (40)
|
|
46
|
+
// is enabled, and app_slug_reconcile (65) runs only on the App route.
|
|
47
|
+
//
|
|
41
48
|
// vm_inventory (68) VM only: the deploy inventory, from the answers;
|
|
42
49
|
// vm_deploy (71) VM only: `scripts/deploy.sh`, composed, with every
|
|
43
50
|
// preflight it has — the peer of bringup (70), which is
|
|
@@ -51,6 +58,10 @@ export function defaultSteps(): OnboardingStep[] {
|
|
|
51
58
|
topologyStep(),
|
|
52
59
|
sshPreflightStep(),
|
|
53
60
|
llmAuthStep(),
|
|
61
|
+
// github_account (33) before the interview (35): the interview asks the
|
|
62
|
+
// App questions only on the App route, and takes the repo and login the
|
|
63
|
+
// own-account route already settled.
|
|
64
|
+
githubAccountStep(),
|
|
54
65
|
configFillStep(),
|
|
55
66
|
escalationStep(),
|
|
56
67
|
embeddingsStep(),
|
|
@@ -18,11 +18,18 @@
|
|
|
18
18
|
// permanent hostname (the VM route's default). No rotation, so no
|
|
19
19
|
// self-heal: `[ingress] shape = "none"` and `[server] hostname`
|
|
20
20
|
// carries the name.
|
|
21
|
-
// polling No tunnel at all
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
21
|
+
// polling No tunnel at all — THE DEFAULT on every route, and the only
|
|
22
|
+
// shape the own-account route (`[github] auth = "user"`) allows.
|
|
23
|
+
// `[ingress] shape = "polling"`. The reconcile poll becomes the ONLY
|
|
24
|
+
// trigger path, at `[daemon] poll_interval_s`. What degrades is
|
|
25
|
+
// stated plainly in the step's own output (author-reply routing and
|
|
26
|
+
// the [feedback] loop are webhook-only), and the tunnel is offered
|
|
27
|
+
// as a later upgrade — re-running this step is the upgrade.
|
|
28
|
+
//
|
|
29
|
+
// Called with no choice and none recorded, the step applies the default
|
|
30
|
+
// (polling) and says so in one plain line, with the other shapes listed as
|
|
31
|
+
// the later upgrade: a stated default is not a guess, and nothing about it is
|
|
32
|
+
// irreversible.
|
|
26
33
|
//
|
|
27
34
|
// The step is deliberately self-contained: it owns the `[ingress]` section of
|
|
28
35
|
// config.toml, the project `.env`'s COMPOSE_PROFILES line, and nothing else.
|
|
@@ -33,7 +40,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
33
40
|
import { isAbsolute, join } from "node:path";
|
|
34
41
|
import { INGRESS_DEFAULTS } from "../../config.js";
|
|
35
42
|
import { locateSecrets } from "../../install.js";
|
|
36
|
-
import { CHOICE_KEYS, INGRESS_CHOICES, type IngressChoice } from "../choices.js";
|
|
43
|
+
import { CHOICE_KEYS, INGRESS_CHOICES, userAuthRecorded, type IngressChoice } from "../choices.js";
|
|
37
44
|
import { topologyOf } from "./topology.js";
|
|
38
45
|
import {
|
|
39
46
|
readTextOrNull,
|
|
@@ -67,7 +74,7 @@ export interface IngressOption {
|
|
|
67
74
|
/** Honest trade-offs — the good and the bad, in the operator's words. */
|
|
68
75
|
tradeoffs: string[];
|
|
69
76
|
/** `[ingress] shape` this choice configures. */
|
|
70
|
-
shape: "tunnel-file" | "none";
|
|
77
|
+
shape: "tunnel-file" | "none" | "polling";
|
|
71
78
|
/** COMPOSE_PROFILES value ("" ⇒ no sidecar at all). */
|
|
72
79
|
profile: string;
|
|
73
80
|
/** Secrets-dir file this choice requires, if any. */
|
|
@@ -78,7 +85,7 @@ export interface IngressOption {
|
|
|
78
85
|
|
|
79
86
|
const INGRESS_OPTION_METADATA = {
|
|
80
87
|
quick: {
|
|
81
|
-
headline: "Cloudflare quick tunnel
|
|
88
|
+
headline: "Cloudflare quick tunnel — no account, nothing to sign up for",
|
|
82
89
|
tradeoffs: [
|
|
83
90
|
"no account, no credential, no DNS: it works within seconds of `docker compose up`",
|
|
84
91
|
"the *.trycloudflare.com hostname ROTATES on every tunnel restart — the daemon re-points the App's webhook URL itself, so this costs you nothing to operate",
|
|
@@ -117,14 +124,14 @@ const INGRESS_OPTION_METADATA = {
|
|
|
117
124
|
service: "tunnel-named",
|
|
118
125
|
},
|
|
119
126
|
polling: {
|
|
120
|
-
headline: "Polling only — no tunnel, nothing exposed",
|
|
127
|
+
headline: "Polling only (default) — no tunnel, nothing exposed",
|
|
121
128
|
tradeoffs: [
|
|
122
129
|
"nothing to install, nothing reachable from the internet: the daemon only makes outbound calls",
|
|
123
130
|
"the reconcile poll becomes the ONLY trigger path, so a review starts up to one poll interval late ([daemon] poll_interval_s, 300s by default)",
|
|
124
131
|
"what degrades, plainly: author replies do not route to the PR's session (the ping-pong path is webhook-driven), the [feedback] tuning loop never sees a comment, and the CI-completed retry of a withheld approval waits for the next sweep",
|
|
125
132
|
"it is not a dead end — re-run this step later and pick a tunnel; nothing else has to change",
|
|
126
133
|
],
|
|
127
|
-
shape: "
|
|
134
|
+
shape: "polling",
|
|
128
135
|
profile: "",
|
|
129
136
|
secret: null,
|
|
130
137
|
service: null,
|
|
@@ -163,6 +170,16 @@ const INGRESS_ANCHOR = /^\[daemon\]/m;
|
|
|
163
170
|
|
|
164
171
|
/** The section body (header line included) for a choice. */
|
|
165
172
|
export function ingressBlock(option: IngressOption): string {
|
|
173
|
+
if (option.shape === "polling") {
|
|
174
|
+
return [
|
|
175
|
+
"[ingress]",
|
|
176
|
+
"# Written by the onboarding wizard.",
|
|
177
|
+
"# Chosen shape: polling — no webhook reaches this daemon; the reconcile poll",
|
|
178
|
+
"# ([daemon] poll_interval_s) is the only trigger path.",
|
|
179
|
+
'shape = "polling"',
|
|
180
|
+
"",
|
|
181
|
+
].join("\n");
|
|
182
|
+
}
|
|
166
183
|
if (option.shape === "none") {
|
|
167
184
|
return [
|
|
168
185
|
"[ingress]",
|
|
@@ -425,35 +442,62 @@ function chosen(ctx: StepContext): IngressChoice | null {
|
|
|
425
442
|
}
|
|
426
443
|
|
|
427
444
|
/**
|
|
428
|
-
* The recommended default
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
* front the daemon's port yourself", which the inventory step spells out.
|
|
445
|
+
* The recommended default is polling on every topology: nothing to install,
|
|
446
|
+
* nothing exposed, and the only shape the own-account route allows. A tunnel
|
|
447
|
+
* (quick on a laptop, named on a server) is the later upgrade for webhook
|
|
448
|
+
* latency and the reply-driven paths. Every option stays selectable on both
|
|
449
|
+
* topologies — on the server route the ones the playbook does not install mean
|
|
450
|
+
* "you front the daemon's port yourself", which the inventory step spells out.
|
|
435
451
|
*/
|
|
436
|
-
export function recommendedIngressFor(
|
|
437
|
-
return
|
|
452
|
+
export function recommendedIngressFor(_topology: string): IngressChoice {
|
|
453
|
+
return "polling";
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/** The reconcile poll's interval in whole minutes, as the config states it
|
|
457
|
+
* (the shipped default when it does not). */
|
|
458
|
+
export function pollMinutes(configText: string | null): number {
|
|
459
|
+
const raw = configText ? readTomlKey(configText, "daemon", "poll_interval_s") : null;
|
|
460
|
+
const seconds = raw !== null && /^\d+$/.test(raw.trim()) ? Number(raw.trim()) : 300;
|
|
461
|
+
return Math.max(1, Math.round(seconds / 60));
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** The one plain line the default is applied with. */
|
|
465
|
+
export function pollingDefaultLine(configText: string | null): string {
|
|
466
|
+
return (
|
|
467
|
+
`polling: the reviewer checks GitHub every ${pollMinutes(configText)} minutes for pull requests to review — ` +
|
|
468
|
+
"nothing to set up, nothing exposed to the internet. Webhooks (faster starts, author replies) are optional and " +
|
|
469
|
+
"can be added later by re-running this step with a tunnel choice."
|
|
470
|
+
);
|
|
438
471
|
}
|
|
439
472
|
|
|
440
473
|
function offerCheck(topology: string): CheckResult {
|
|
441
|
-
const recommended = recommendedIngressFor(topology);
|
|
442
474
|
return {
|
|
443
475
|
name: "choice",
|
|
444
476
|
ok: false,
|
|
445
477
|
detail:
|
|
446
478
|
`pick one of ${CHOICE_IDS.join(" | ")} and call this step again with it (choice: "<id>").\n` +
|
|
479
|
+
`The default is "${recommendedIngressFor(topology)}" — nothing to set up and nothing exposed; webhooks are a later upgrade.` +
|
|
447
480
|
(topology === "vm"
|
|
448
|
-
?
|
|
449
|
-
"your tunnel token, and
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
"re-points its own webhook URL when the hostname rotates.\n") +
|
|
481
|
+
? " On the server route the named tunnel is the upgrade worth having: the deploy installs cloudflared on that machine " +
|
|
482
|
+
"from your tunnel token, and a hostname that never rotates. quick/ngrok mean you run that tunnel on the server yourself.\n"
|
|
483
|
+
: " On this machine the quick tunnel is the no-account upgrade: the daemon re-points its own webhook URL when the " +
|
|
484
|
+
"hostname rotates.\n") +
|
|
453
485
|
renderOptions(),
|
|
454
486
|
};
|
|
455
487
|
}
|
|
456
488
|
|
|
489
|
+
/** The own-account route has no webhook: no App exists to deliver one. */
|
|
490
|
+
function userRouteRefusal(choice: IngressChoice): CheckResult {
|
|
491
|
+
return {
|
|
492
|
+
name: "choice",
|
|
493
|
+
ok: false,
|
|
494
|
+
detail:
|
|
495
|
+
`"${choice}" needs webhooks, and the own-account GitHub route ([github] auth = "user") has none — webhooks are ` +
|
|
496
|
+
'delivered to a GitHub App, and this install runs on your own account instead. It is polling only: run this step with choice: "polling" ' +
|
|
497
|
+
'(or with no choice). To use webhooks, switch to the App route first: the github_account step with github_auth: "app".',
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
457
501
|
function credentialPresent(file: string): boolean {
|
|
458
502
|
return existsSync(file) && readFileSync(file, "utf8").trim() !== "";
|
|
459
503
|
}
|
|
@@ -464,7 +508,7 @@ export function ingressStep(opts: { stream?: StreamRunner } = {}): OnboardingSte
|
|
|
464
508
|
title: "Webhook ingress: how GitHub reaches your daemon",
|
|
465
509
|
explain:
|
|
466
510
|
"GitHub delivers webhooks to an HTTPS URL, so your daemon needs one. Offer the four shapes with their real " +
|
|
467
|
-
"trade-offs — quick tunnel (
|
|
511
|
+
"trade-offs — quick tunnel (no account, rotating hostname the daemon re-points itself), ngrok " +
|
|
468
512
|
"(stable hostname, free-tier caps), a named Cloudflare tunnel (your own domain), or polling-only (no tunnel; " +
|
|
469
513
|
"the reconcile poll triggers reviews, and author-reply routing plus the feedback loop go quiet). The recommended " +
|
|
470
514
|
"answer depends on where the reviewer lives: the quick tunnel on this computer, the named tunnel on a server (the " +
|
|
@@ -493,13 +537,32 @@ export function ingressStep(opts: { stream?: StreamRunner } = {}): OnboardingSte
|
|
|
493
537
|
},
|
|
494
538
|
|
|
495
539
|
async run(ctx): Promise<StepReport> {
|
|
496
|
-
const
|
|
497
|
-
|
|
540
|
+
const userRoute = userAuthRecorded(ctx.choices);
|
|
541
|
+
const typed = ctx.input.choice;
|
|
542
|
+
const typedAnswer = typeof typed === "string" && typed.trim() !== "";
|
|
543
|
+
let choice = chosen(ctx);
|
|
544
|
+
// An answer that names no shape is re-offered, never defaulted over.
|
|
545
|
+
if (choice === null && typedAnswer)
|
|
498
546
|
return { ok: false, checks: [offerCheck(String(ctx.choices[CHOICE_KEYS.topology] ?? ""))] };
|
|
547
|
+
const defaulted = choice === null;
|
|
548
|
+
if (choice === null)
|
|
549
|
+
choice = recommendedIngressFor(String(ctx.choices[CHOICE_KEYS.topology] ?? ""));
|
|
550
|
+
if (userRoute && choice !== "polling") {
|
|
551
|
+
// A shape recorded before the route was switched is not an answer now.
|
|
552
|
+
if (!typedAnswer) choice = "polling";
|
|
553
|
+
else return { ok: false, checks: [userRouteRefusal(choice)] };
|
|
554
|
+
}
|
|
499
555
|
const option = optionFor(choice)!;
|
|
500
556
|
const root = sandboxRootOf(ctx.adapters);
|
|
501
557
|
const checks: CheckResult[] = [
|
|
502
|
-
{
|
|
558
|
+
{
|
|
559
|
+
name: "choice",
|
|
560
|
+
ok: true,
|
|
561
|
+
detail:
|
|
562
|
+
defaulted && option.id === "polling"
|
|
563
|
+
? `${pollingDefaultLine(readTextOrNull(ctx.adapters.paths.configPath))}\nThe other shapes, for later: ${CHOICE_IDS.filter((id) => id !== "polling").join(", ")}.`
|
|
564
|
+
: `${option.id} — ${option.headline}`,
|
|
565
|
+
},
|
|
503
566
|
{ name: "trade-offs", ok: true, detail: option.tradeoffs.map((t) => `• ${t}`).join("\n") },
|
|
504
567
|
];
|
|
505
568
|
|
|
@@ -580,7 +643,9 @@ export function ingressStep(opts: { stream?: StreamRunner } = {}): OnboardingSte
|
|
|
580
643
|
detail:
|
|
581
644
|
option.shape === "tunnel-file"
|
|
582
645
|
? '[ingress] shape = "tunnel-file" — the daemon watches the hostname file and re-points the App webhook URL when the tunnel rotates'
|
|
583
|
-
:
|
|
646
|
+
: option.shape === "polling"
|
|
647
|
+
? '[ingress] shape = "polling" — no webhook, the reconcile poll is the only trigger path'
|
|
648
|
+
: '[ingress] shape = "none" — no webhook self-heal (this hostname does not rotate)',
|
|
584
649
|
});
|
|
585
650
|
|
|
586
651
|
// 4. the compose profile — which sidecar (if any) comes up with the stack.
|
|
@@ -697,7 +762,9 @@ export function ingressStep(opts: { stream?: StreamRunner } = {}): OnboardingSte
|
|
|
697
762
|
ok: false,
|
|
698
763
|
detail: `${ctx.adapters.paths.configPath} is gone — re-run the ingress step after restoring it`,
|
|
699
764
|
}
|
|
700
|
-
: shape === option.shape
|
|
765
|
+
: shape === option.shape ||
|
|
766
|
+
// a polling install from before the shape had its own name
|
|
767
|
+
(option.id === "polling" && shape === "none" && !userAuthRecorded(ctx.choices))
|
|
701
768
|
? { name: "config", ok: true, detail: `[ingress] shape = "${shape}"` }
|
|
702
769
|
: {
|
|
703
770
|
name: "config",
|