@quickchatai/quickreview 1.1.0 → 1.2.0
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 +35 -19
- package/config.example.toml +41 -9
- package/dist/extensions/cli/login-route.js +5 -0
- package/dist/extensions/cli/login-route.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 +29 -6
- package/dist/extensions/onboarding.js.map +1 -1
- package/dist/src/ciretry.js +2 -1
- package/dist/src/ciretry.js.map +1 -1
- package/dist/src/cli.js +43 -12
- 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 +16 -2
- package/dist/src/config.js.map +1 -1
- package/dist/src/daemon.js +24 -8
- package/dist/src/daemon.js.map +1 -1
- package/dist/src/debugroundpi.js +5 -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/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/loginhint.js +8 -3
- package/dist/src/loginhint.js.map +1 -1
- package/dist/src/loginrefresh/pirefresh.js +3 -0
- package/dist/src/loginrefresh/pirefresh.js.map +1 -1
- package/dist/src/npmverbs.js +4 -2
- package/dist/src/npmverbs.js.map +1 -1
- package/dist/src/onboard/choices.js +29 -1
- package/dist/src/onboard/choices.js.map +1 -1
- package/dist/src/onboard/engine.js +8 -23
- package/dist/src/onboard/engine.js.map +1 -1
- package/dist/src/onboard/launch.js +12 -20
- package/dist/src/onboard/launch.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/compose.js +29 -0
- package/dist/src/onboard/steps/compose.js.map +1 -1
- package/dist/src/onboard/steps/configfill.js +102 -32
- 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/memory.js +53 -1
- 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/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/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/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/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/state.js.map +1 -1
- package/dist/src/statemachine.js +4 -1
- package/dist/src/statemachine.js.map +1 -1
- package/dist/src/takeoverpi.js +13 -0
- 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 +74 -10
- 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/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 +106 -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/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 +29 -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 +28 -6
- package/dist/src/wire.js.map +1 -1
- package/dist/src/workerworld.js +7 -1
- package/dist/src/workerworld.js.map +1 -1
- package/docker/companion/entrypoint.sh +20 -1
- package/docker/entrypoint.sh +17 -0
- package/extensions/cli/login-route.ts +10 -0
- package/extensions/login-route.ts +220 -0
- package/extensions/onboarding.ts +35 -6
- package/package.json +2 -2
- package/prompts/onboarding.md +57 -18
- package/scripts/mint-token.sh +25 -4
- package/src/ciretry.ts +2 -1
- package/src/cli.ts +49 -14
- package/src/cliops.ts +3 -2
- package/src/commands.ts +28 -2
- package/src/config.ts +24 -4
- package/src/daemon.ts +32 -7
- package/src/debugroundpi.ts +11 -1
- package/src/dispatch.ts +5 -4
- 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/loginhint.ts +8 -3
- package/src/loginrefresh/pirefresh.ts +3 -0
- package/src/npmverbs.ts +4 -2
- package/src/onboard/choices.ts +34 -1
- package/src/onboard/engine.ts +22 -3
- package/src/onboard/launch.ts +17 -29
- 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/compose.ts +31 -0
- package/src/onboard/steps/configfill.ts +121 -33
- 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/memory.ts +58 -1
- package/src/onboard/steps/proof.ts +473 -55
- 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/posting-journal.ts +6 -1
- package/src/posting-outbox.ts +10 -2
- package/src/posting-receipt.ts +17 -0
- package/src/recheck.ts +2 -1
- package/src/reconcile.ts +29 -3
- package/src/reviewhistory.ts +20 -6
- package/src/reviewnow.ts +76 -0
- package/src/state.ts +18 -0
- package/src/statemachine.ts +4 -1
- package/src/takeoverpi.ts +13 -0
- 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 +78 -10
- package/src/tui/connect.ts +7 -1
- package/src/tui/filters.ts +7 -3
- package/src/tui/ghread.ts +74 -7
- package/src/tui/index.ts +114 -23
- package/src/tui/memforward.ts +52 -3
- 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 +52 -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 +36 -7
- package/src/workerworld.ts +7 -1
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
type ChoiceName,
|
|
64
64
|
botLoginFor,
|
|
65
65
|
ingressChoiceOf,
|
|
66
|
+
userAuthRecorded,
|
|
66
67
|
type IngressChoice,
|
|
67
68
|
} from "../choices.js";
|
|
68
69
|
import {
|
|
@@ -76,8 +77,8 @@ import {
|
|
|
76
77
|
} from "../engine.js";
|
|
77
78
|
import { deliverConfigChange, configDeliveryChecks } from "./configdelivery.js";
|
|
78
79
|
import type { TransportOptions } from "./transport.js";
|
|
79
|
-
import { BARE_HOSTNAME_RE, readTomlKey, secretsDirFor } from "./ingress.js";
|
|
80
|
-
import { SSH_ALIAS_RE } from "./topology.js";
|
|
80
|
+
import { BARE_HOSTNAME_RE, CONTAINER_STATE_DIR, readTomlKey, secretsDirFor } from "./ingress.js";
|
|
81
|
+
import { SSH_ALIAS_RE, topologyOf, type Topology } from "./topology.js";
|
|
81
82
|
|
|
82
83
|
export const CONFIG_FILL_STEP_ID = "config_fill";
|
|
83
84
|
|
|
@@ -228,9 +229,17 @@ export interface FillFacts {
|
|
|
228
229
|
secrets_dir: string;
|
|
229
230
|
topology: string;
|
|
230
231
|
ingress: string;
|
|
232
|
+
/** The GitHub route the github_account step recorded ("user" | "app"), ""
|
|
233
|
+
* while unanswered — which is the App route's interview. */
|
|
234
|
+
github_auth?: string;
|
|
235
|
+
/** The person's own login on the "user" route (`GET /user`). */
|
|
236
|
+
account_login?: string;
|
|
231
237
|
}
|
|
232
238
|
|
|
233
|
-
export type AnswerKey = Exclude<
|
|
239
|
+
export type AnswerKey = Exclude<
|
|
240
|
+
keyof FillFacts,
|
|
241
|
+
"secrets_dir" | "topology" | "ingress" | "github_auth" | "account_login"
|
|
242
|
+
>;
|
|
234
243
|
|
|
235
244
|
export interface Question {
|
|
236
245
|
id: AnswerKey;
|
|
@@ -282,7 +291,9 @@ export const QUESTIONS: readonly Question[] = [
|
|
|
282
291
|
"clone directory, backfill identity — is derived from this one answer.",
|
|
283
292
|
prompt: 'Which repository should the reviewer watch? ("owner/name")',
|
|
284
293
|
optional: false,
|
|
285
|
-
|
|
294
|
+
// On the own-account route the github_account step already asked, from
|
|
295
|
+
// the repos the person's account reaches.
|
|
296
|
+
from: [CHOICE_KEYS.accountRepo, CHOICE_KEYS.repo],
|
|
286
297
|
read: (cfg) => cfg.github.repo,
|
|
287
298
|
validate: (v) =>
|
|
288
299
|
REPO_SLUG_RE.test(v)
|
|
@@ -298,8 +309,10 @@ export const QUESTIONS: readonly Question[] = [
|
|
|
298
309
|
"The companion — the local pi that sits beside the TUI — reads the code a review is about. Your checkout is " +
|
|
299
310
|
"mounted READ-ONLY into its container: it can read every file and change none of them. A missing checkout only " +
|
|
300
311
|
"makes the companion less informed; it never breaks the reviewer.",
|
|
301
|
-
prompt:
|
|
302
|
-
|
|
312
|
+
prompt:
|
|
313
|
+
"Where is your local checkout of that repository? (Enter if there is none here — the companion starts without it)",
|
|
314
|
+
// A fresh box has no checkout, and the daemon clones the repository itself.
|
|
315
|
+
optional: true,
|
|
303
316
|
from: [CHOICE_KEYS.repoDir],
|
|
304
317
|
read: (cfg) => cfg.companion.reviewed_repo_dir,
|
|
305
318
|
validate: (v) => {
|
|
@@ -325,6 +338,8 @@ export const QUESTIONS: readonly Question[] = [
|
|
|
325
338
|
prompt: "What is your GitHub App's slug?",
|
|
326
339
|
optional: false,
|
|
327
340
|
from: [CHOICE_KEYS.appSlug],
|
|
341
|
+
// No App exists on the own-account route: `[github] app_slug` stays "".
|
|
342
|
+
asked: (choices) => !userAuthRecorded(choices),
|
|
328
343
|
read: (cfg) => cfg.github.app_slug,
|
|
329
344
|
validate: (v) =>
|
|
330
345
|
SLUG_RE.test(v)
|
|
@@ -390,7 +405,7 @@ export const QUESTIONS: readonly Question[] = [
|
|
|
390
405
|
"It is never used to authenticate anything — the App credential is the only identity that acts.",
|
|
391
406
|
prompt: "What is your GitHub login? (Enter to skip)",
|
|
392
407
|
optional: true,
|
|
393
|
-
from: [CHOICE_KEYS.ownerLogin],
|
|
408
|
+
from: [CHOICE_KEYS.accountLogin, CHOICE_KEYS.ownerLogin],
|
|
394
409
|
read: (cfg) => cfg.owner.github_login,
|
|
395
410
|
validate: validateGithubLogin,
|
|
396
411
|
},
|
|
@@ -493,27 +508,51 @@ export interface Derivable {
|
|
|
493
508
|
holds(cfg: Config, facts: FillFacts): string | null;
|
|
494
509
|
}
|
|
495
510
|
|
|
496
|
-
/** The
|
|
497
|
-
|
|
498
|
-
|
|
511
|
+
/** The topology a fill is for: the recorded one, and "local" while none is
|
|
512
|
+
* recorded — `topologyOf`'s reading, the one every other step uses. */
|
|
513
|
+
function fillTopology(topology: string): Topology {
|
|
514
|
+
return topologyOf({ [CHOICE_KEYS.topology]: topology });
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/** The TUI transport a topology implies (an unrecorded one is local). */
|
|
518
|
+
function tuiTargetFor(topology: string): "local" | "ssh" {
|
|
519
|
+
return fillTopology(topology) === "vm" ? "ssh" : "local";
|
|
499
520
|
}
|
|
500
521
|
|
|
522
|
+
/** The release image's state dir inside the compose daemon container (the
|
|
523
|
+
* `qcr-state` volume), where the local TUI reads status.json. */
|
|
524
|
+
const LOCAL_TUI_STATE_DIR = CONTAINER_STATE_DIR;
|
|
525
|
+
|
|
501
526
|
export const DERIVABLES: readonly Derivable[] = [
|
|
502
527
|
{
|
|
503
528
|
id: "bot_login",
|
|
504
529
|
path: "[github] bot_login",
|
|
505
530
|
explain:
|
|
506
|
-
"the bot login is the App slug plus the [bot] suffix — asking for it twice is how the two drift apart"
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
531
|
+
"the bot login is the App slug plus the [bot] suffix — asking for it twice is how the two drift apart. On your own " +
|
|
532
|
+
"GitHub account it is your login: the reviews are posted as you",
|
|
533
|
+
write: (f) =>
|
|
534
|
+
f.github_auth === "user"
|
|
535
|
+
? f.account_login
|
|
536
|
+
? { section: "github", key: "bot_login", value: tomlString(f.account_login) }
|
|
537
|
+
: null
|
|
538
|
+
: {
|
|
539
|
+
section: "github",
|
|
540
|
+
key: "bot_login",
|
|
541
|
+
value: tomlString(botLoginFor(f.app_slug)),
|
|
542
|
+
},
|
|
512
543
|
stable: true,
|
|
513
|
-
holds: (cfg) =>
|
|
514
|
-
|
|
544
|
+
holds: (cfg, f) => {
|
|
545
|
+
if (f.github_auth === "user") {
|
|
546
|
+
if (!cfg.github.bot_login.trim())
|
|
547
|
+
return "[github] bot_login is empty — on your own account it is your GitHub login; run the github_account step";
|
|
548
|
+
return f.account_login && cfg.github.bot_login !== f.account_login
|
|
549
|
+
? `[github] bot_login is "${cfg.github.bot_login}" but your account is "${f.account_login}" — run the github_account step again`
|
|
550
|
+
: null;
|
|
551
|
+
}
|
|
552
|
+
return cfg.github.bot_login === botLoginFor(cfg.github.app_slug)
|
|
515
553
|
? null
|
|
516
|
-
: `[github] bot_login is "${cfg.github.bot_login}" but the App slug "${cfg.github.app_slug}" implies "${botLoginFor(cfg.github.app_slug)}"
|
|
554
|
+
: `[github] bot_login is "${cfg.github.bot_login}" but the App slug "${cfg.github.app_slug}" implies "${botLoginFor(cfg.github.app_slug)}"`;
|
|
555
|
+
},
|
|
517
556
|
},
|
|
518
557
|
{
|
|
519
558
|
id: "clone_dir",
|
|
@@ -547,7 +586,7 @@ export const DERIVABLES: readonly Derivable[] = [
|
|
|
547
586
|
holds: (cfg) =>
|
|
548
587
|
cfg.github.secrets_dir.trim()
|
|
549
588
|
? null
|
|
550
|
-
: "[github] secrets_dir is empty — the
|
|
589
|
+
: "[github] secrets_dir is empty — the GitHub credential has nowhere to live",
|
|
551
590
|
},
|
|
552
591
|
{
|
|
553
592
|
id: "review_team",
|
|
@@ -588,10 +627,12 @@ export const DERIVABLES: readonly Derivable[] = [
|
|
|
588
627
|
"the history importer's identity and labels cascade off [github] — never a second copy to keep in sync",
|
|
589
628
|
write: () => null,
|
|
590
629
|
stable: true,
|
|
591
|
-
holds: (cfg) => {
|
|
630
|
+
holds: (cfg, f) => {
|
|
592
631
|
if (cfg.backfill.bot_login !== cfg.github.bot_login)
|
|
593
632
|
return "[backfill] bot_login no longer follows [github] bot_login";
|
|
594
|
-
|
|
633
|
+
// The actor is the App slug; the own-account route has no App, and the
|
|
634
|
+
// loader decides what stands in for it there.
|
|
635
|
+
if (f.github_auth !== "user" && cfg.backfill.bot_actor !== cfg.github.app_slug)
|
|
595
636
|
return "[backfill] bot_actor no longer follows [github] app_slug";
|
|
596
637
|
if (cfg.backfill.trigger_label !== cfg.github.trigger_label)
|
|
597
638
|
return "[backfill] trigger_label no longer follows [github] trigger_label";
|
|
@@ -615,15 +656,12 @@ export const DERIVABLES: readonly Derivable[] = [
|
|
|
615
656
|
path: "[tui] target",
|
|
616
657
|
explain:
|
|
617
658
|
'follows the recorded topology: "local" when the daemon runs on this machine (the TUI talks to local Docker), "ssh" on the VM route',
|
|
618
|
-
write: (f) => {
|
|
619
|
-
const target = tuiTargetFor(f.topology);
|
|
620
|
-
return target ? { section: "tui", key: "target", value: tomlString(target) } : null;
|
|
621
|
-
},
|
|
659
|
+
write: (f) => ({ section: "tui", key: "target", value: tomlString(tuiTargetFor(f.topology)) }),
|
|
622
660
|
stable: true,
|
|
623
661
|
holds: (cfg, f) => {
|
|
624
662
|
const want = tuiTargetFor(f.topology);
|
|
625
|
-
return
|
|
626
|
-
? `[tui] target = "${cfg.tui.target}", but the
|
|
663
|
+
return cfg.tui.target !== want
|
|
664
|
+
? `[tui] target = "${cfg.tui.target}", but the topology is ${f.topology || "local (none recorded)"} — the TUI would ` +
|
|
627
665
|
`${want === "local" ? "look for the daemon over ssh" : "look for the daemon in local Docker"}. ` +
|
|
628
666
|
`Fix: run this step again (it writes target = "${want}")`
|
|
629
667
|
: null;
|
|
@@ -635,7 +673,8 @@ export const DERIVABLES: readonly Derivable[] = [
|
|
|
635
673
|
explain:
|
|
636
674
|
"the bundled local Compose project runs service daemon as quickreview-daemon-1; preserve an operator's custom container",
|
|
637
675
|
write: (f, fresh, existing) =>
|
|
638
|
-
f.topology === "local" &&
|
|
676
|
+
fillTopology(f.topology) === "local" &&
|
|
677
|
+
(fresh || existing?.tui.container === TUI_DEFAULTS.container)
|
|
639
678
|
? { section: "tui", key: "container", value: tomlString("quickreview-daemon-1") }
|
|
640
679
|
: null,
|
|
641
680
|
stable: false,
|
|
@@ -647,12 +686,41 @@ export const DERIVABLES: readonly Derivable[] = [
|
|
|
647
686
|
explain:
|
|
648
687
|
"the bundled local Compose project runs the memory sidecar as quickreview-memory-1, where the memory forward must relay; preserve an operator's custom container",
|
|
649
688
|
write: (f, fresh, existing) =>
|
|
650
|
-
f.topology === "local" &&
|
|
689
|
+
fillTopology(f.topology) === "local" &&
|
|
690
|
+
(fresh || (existing?.tui.memory_container ?? "") === "")
|
|
651
691
|
? { section: "tui", key: "memory_container", value: tomlString("quickreview-memory-1") }
|
|
652
692
|
: null,
|
|
653
693
|
stable: false,
|
|
654
694
|
holds: () => null,
|
|
655
695
|
},
|
|
696
|
+
{
|
|
697
|
+
id: "tui_remote_state_dir",
|
|
698
|
+
path: "[tui] remote_state_dir",
|
|
699
|
+
explain:
|
|
700
|
+
`on this machine the TUI reads status.json inside the daemon container, where the release image keeps its state (${LOCAL_TUI_STATE_DIR}, ` +
|
|
701
|
+
"the compose state volume) — the shipped default is the VM host's path; preserve an operator's custom path",
|
|
702
|
+
write: (f, fresh, existing) =>
|
|
703
|
+
fillTopology(f.topology) === "local" &&
|
|
704
|
+
(fresh || existing?.tui.remote_state_dir === TUI_DEFAULTS.remote_state_dir)
|
|
705
|
+
? { section: "tui", key: "remote_state_dir", value: tomlString(LOCAL_TUI_STATE_DIR) }
|
|
706
|
+
: null,
|
|
707
|
+
stable: false,
|
|
708
|
+
holds: () => null,
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
id: "tui_sudo_docker",
|
|
712
|
+
path: "[tui] sudo_docker",
|
|
713
|
+
explain:
|
|
714
|
+
"off on this machine: the wizard's own bring-up drives docker without sudo, so the TUI does too (a sudo password " +
|
|
715
|
+
"prompt behind the TUI's screen can only fail); on the VM route sudo stays the shipped default",
|
|
716
|
+
write: (f, fresh, existing) =>
|
|
717
|
+
fillTopology(f.topology) === "local" &&
|
|
718
|
+
(fresh || existing?.tui.sudo_docker === TUI_DEFAULTS.sudo_docker)
|
|
719
|
+
? { section: "tui", key: "sudo_docker", value: "false" }
|
|
720
|
+
: null,
|
|
721
|
+
stable: false,
|
|
722
|
+
holds: () => null,
|
|
723
|
+
},
|
|
656
724
|
{
|
|
657
725
|
id: "tui_ssh_host",
|
|
658
726
|
path: "[tui] ssh_host",
|
|
@@ -729,6 +797,9 @@ export const DEFAULT_SECRETS_DIR = "";
|
|
|
729
797
|
* Read from ITS artefacts (the `deploy_shape` marker it writes) so this step
|
|
730
798
|
* reports the same required set without duplicating the wizard's validators. */
|
|
731
799
|
export const REQUIRED_SECRETS: readonly string[] = ["app_id", "app.pem", "webhook_secret"];
|
|
800
|
+
/** The own-account route's one secret: the person's token, written by
|
|
801
|
+
* `qcr github-token sync` (the github_account step runs it). */
|
|
802
|
+
export const USER_ROUTE_SECRETS: readonly string[] = ["github_token"];
|
|
732
803
|
export const TUNNEL_SHAPE_SECRET = "tunnel_token";
|
|
733
804
|
|
|
734
805
|
/** Unlike `readTextOrNull`, only ABSENCE is null: a file that exists and
|
|
@@ -918,6 +989,8 @@ export async function collectAnswers(
|
|
|
918
989
|
DEFAULT_SECRETS_DIR,
|
|
919
990
|
topology: str(choices, CHOICE_KEYS.topology),
|
|
920
991
|
ingress: str(choices, CHOICE_KEYS.ingress),
|
|
992
|
+
github_auth: str(choices, CHOICE_KEYS.githubAuth),
|
|
993
|
+
account_login: str(choices, CHOICE_KEYS.accountLogin),
|
|
921
994
|
};
|
|
922
995
|
return { facts, missing, rejected, asked, ignored };
|
|
923
996
|
}
|
|
@@ -992,7 +1065,17 @@ export function changedEdits(text: string, edits: readonly TomlEdit[]): TomlEdit
|
|
|
992
1065
|
}
|
|
993
1066
|
|
|
994
1067
|
/** What the secrets dir holds, at the one resolution every step uses. */
|
|
995
|
-
function secretsReport(dir: string): CheckResult {
|
|
1068
|
+
function secretsReport(dir: string, userRoute: boolean): CheckResult {
|
|
1069
|
+
if (userRoute) {
|
|
1070
|
+
const missing = USER_ROUTE_SECRETS.filter((f) => !existsSync(join(dir, f)));
|
|
1071
|
+
return {
|
|
1072
|
+
name: "secrets",
|
|
1073
|
+
ok: true,
|
|
1074
|
+
detail: missing.length
|
|
1075
|
+
? `${dir}: still missing ${missing.join(", ")} — the github_account step writes it from your GitHub sign-in (no App secrets on this route)`
|
|
1076
|
+
: `${dir}: your GitHub token is present — the own-account route needs no App secrets`,
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
996
1079
|
if (!existsSync(dir)) {
|
|
997
1080
|
return {
|
|
998
1081
|
name: "secrets",
|
|
@@ -1221,11 +1304,14 @@ export function configFillStep(opts: { transport?: TransportOptions } = {}): Onb
|
|
|
1221
1304
|
ok: true,
|
|
1222
1305
|
detail:
|
|
1223
1306
|
`topology ${facts.topology || "(unrecorded — filled for a daemon on this machine, so [tui] ssh_host stays empty)"}, ` +
|
|
1224
|
-
`ingress ${facts.ingress || "(unrecorded — filled for an ingress that assigns its own hostname, so [server] hostname stays empty)"}` +
|
|
1307
|
+
`ingress ${facts.ingress || "(unrecorded — filled for an ingress that assigns its own hostname, so [server] hostname stays empty)"}, ` +
|
|
1308
|
+
`github ${facts.github_auth === "user" ? "own account (no App questions, no App secrets)" : "App"}` +
|
|
1225
1309
|
`${str(ctx.choices, CHOICE_KEYS.authRoute) ? `, auth route ${str(ctx.choices, CHOICE_KEYS.authRoute)}` : ""}`,
|
|
1226
1310
|
});
|
|
1227
1311
|
// Read after the write, so the dir is the one the written config names.
|
|
1228
|
-
checks.push(
|
|
1312
|
+
checks.push(
|
|
1313
|
+
secretsReport(secretsDirFor(ctx.adapters, ctx.choices), userAuthRecorded(ctx.choices)),
|
|
1314
|
+
);
|
|
1229
1315
|
|
|
1230
1316
|
const ok = checks.every((c) => c.ok);
|
|
1231
1317
|
if (ok) recordChoices(ctx, facts, configPath, parsed);
|
|
@@ -1320,6 +1406,8 @@ export function configFillStep(opts: { transport?: TransportOptions } = {}): Onb
|
|
|
1320
1406
|
secrets_dir: cfg.github.secrets_dir,
|
|
1321
1407
|
topology: str(ctx.choices, CHOICE_KEYS.topology),
|
|
1322
1408
|
ingress: str(ctx.choices, CHOICE_KEYS.ingress),
|
|
1409
|
+
github_auth: str(ctx.choices, CHOICE_KEYS.githubAuth),
|
|
1410
|
+
account_login: str(ctx.choices, CHOICE_KEYS.accountLogin),
|
|
1323
1411
|
};
|
|
1324
1412
|
for (const d of DERIVABLES) {
|
|
1325
1413
|
if (!d.stable) continue;
|