@catalyst-cloud/cli 0.15.2 → 0.15.3
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/CHANGELOG.md +7 -0
- package/README.md +2 -2
- package/dist/cli.js +5 -17
- package/dist/oauth.js +1 -1
- package/dist/onboard-accounts.js +67 -171
- package/dist/onboard-checklist.js +309 -0
- package/dist/onboard-existing.js +1 -1
- package/dist/onboard-first-ticket.js +199 -0
- package/dist/onboard-headless.js +2 -2
- package/dist/onboard-housekeeping.js +93 -0
- package/dist/onboard-next.js +108 -9
- package/dist/onboard-ready.js +61 -0
- package/dist/onboard-runtime.js +60 -27
- package/dist/onboard-standalone-copy.js +73 -66
- package/dist/onboard-ui.js +162 -89
- package/dist/onboard-values.js +47 -0
- package/dist/onboard.js +49 -13
- package/dist/ready-copy.js +87 -0
- package/dist/ready.js +1 -57
- package/dist/setup-onboard-copy.js +237 -41
- package/dist/setup-render.js +73 -16
- package/dist/setup.js +6 -3
- package/package.json +1 -1
- package/skills/catalyst-github/SKILL.md +1 -1
- package/skills/catalyst-linear/SKILL.md +1 -1
- package/skills/catalyst-onboard/SKILL.md +3 -3
- package/skills/catalyst-onboard/references/replacing-a-credential.md +9 -15
- package/skills/catalyst-onboard/references/what-a-phase-needs.md +4 -11
- package/skills/catalyst-onboard/scripts/where-am-i.mjs +1 -1
- package/skills/run-this-project/SKILL.md +2 -2
- package/skills/unstick/SKILL.md +1 -1
- package/skills/what-needs-me/SKILL.md +1 -1
- package/skills/what-this-repo-needs/SKILL.md +1 -1
- package/skills/whats-happening/SKILL.md +2 -2
- package/skills/whats-happening/references/coding-accounts.md +1 -1
- package/skills/whats-happening/scripts/snapshot.mjs +1 -1
package/dist/onboard-ui.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { COMPUTER_CHECKS, standalonePlan, standalonePlanNotes, pendingContinuation, } from "./onboard-standalone-copy.js";
|
|
2
2
|
import { trackedPrompt } from "./setup-prompt-frame.js";
|
|
3
3
|
import { createOnboardInterrupts } from "./onboard-interrupts.js";
|
|
4
|
-
import { setupStepView, CONNECTION_REPAIR_REASONS, setupFinalScreen, setupBrowserInstruction,
|
|
4
|
+
import { setupStepView, CONNECTION_REPAIR_REASONS, setupFinalScreen, setupBrowserInstruction, setupCommandWords as say, setupPartHeading, setupPartProgress, setupTrackerRows, SETUP_PART_NUMBERS, SETUP_PART_OF, SETUP_PARTS, } from "./setup-onboard-copy.js";
|
|
5
5
|
import { createOnboardProgress, } from "./onboard-progress.js";
|
|
6
6
|
import { CREATE_TEAM_CHOICE, suggestTeamKey, teamKeyProblem, teamNameProblem, } from "./onboard-team-create.js";
|
|
7
|
+
import { FIRST_TICKET_SAMPLE, FIRST_TICKET_SKIP, } from "./onboard-first-ticket.js";
|
|
7
8
|
import { ONBOARD_STEPS, ONBOARD_TITLES, stepSatisfied, onboardIdentityLines, onboardNextActions, onboardReadyForWork, onboardStepAction, } from "./onboard.js";
|
|
8
9
|
import { onboardStepDetail, onboardReasonText } from "./onboard-next.js";
|
|
9
10
|
export function shouldUseOnboardUi(args, stdoutTty) {
|
|
@@ -12,25 +13,6 @@ export function shouldUseOnboardUi(args, stdoutTty) {
|
|
|
12
13
|
args.flags.yes !== true &&
|
|
13
14
|
args.flags["dry-run"] !== true);
|
|
14
15
|
}
|
|
15
|
-
export const STEP_NUMBERS = {
|
|
16
|
-
signin: 4,
|
|
17
|
-
housekeeping: 5,
|
|
18
|
-
"linear.workspace": 6,
|
|
19
|
-
"linear.personal": 7,
|
|
20
|
-
"linear.team": 8,
|
|
21
|
-
"linear.adopt": 9,
|
|
22
|
-
"linear.automations": 10,
|
|
23
|
-
"github.install": 11,
|
|
24
|
-
"github.personal": 12,
|
|
25
|
-
"github.repos": 13,
|
|
26
|
-
projects: 13,
|
|
27
|
-
accounts: 14,
|
|
28
|
-
capacity: 15,
|
|
29
|
-
runner: 15,
|
|
30
|
-
settings: 16,
|
|
31
|
-
values: 16,
|
|
32
|
-
"first-ticket": 17,
|
|
33
|
-
};
|
|
34
16
|
export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
35
17
|
const abort = new AbortController();
|
|
36
18
|
const options = { ...streams, signal: abort.signal };
|
|
@@ -52,6 +34,15 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
52
34
|
const renderer = deps.renderer;
|
|
53
35
|
const interactive = deps.interactive !== false;
|
|
54
36
|
let group;
|
|
37
|
+
// CTC-4680: the part whose steps are on screen, the journal and plan the tracker reads, and
|
|
38
|
+
// whether boundaries draw the tracker (not on a check-again pass).
|
|
39
|
+
let part;
|
|
40
|
+
// The part of the last step that ended in this run, shown or not: a boundary is a move past it.
|
|
41
|
+
let ranPart;
|
|
42
|
+
let journalSeen;
|
|
43
|
+
let planned = {};
|
|
44
|
+
let rechecking = false;
|
|
45
|
+
let shownPlan;
|
|
55
46
|
let browserOpened = true;
|
|
56
47
|
let questionOpen = false;
|
|
57
48
|
let signinShown = false;
|
|
@@ -81,6 +72,41 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
81
72
|
].includes(id))) &&
|
|
82
73
|
!(id === "signin" && signinShown));
|
|
83
74
|
const title = (id) => setupStepView({ id, state: "running" }).title;
|
|
75
|
+
const number = (id) => SETUP_PART_NUMBERS[id] ?? 0;
|
|
76
|
+
/** A part's heading, then its plan rows, numbered from 1. */
|
|
77
|
+
const planPart = (r, p, journal) => {
|
|
78
|
+
r.heading(setupPartHeading(p, r.traits.unicode));
|
|
79
|
+
for (const row of standalonePlan(journal, planned.scope, planned.runner))
|
|
80
|
+
if (row.part === p)
|
|
81
|
+
r.plan(row.number, row.title, row.detail);
|
|
82
|
+
};
|
|
83
|
+
/** Starting a step in another part: its heading, and when this run has moved past a part, the
|
|
84
|
+
* tracker again with the new part's plan. After the install engine, part 1's checks run unshown,
|
|
85
|
+
* so setup opens on the part 1 boundary. */
|
|
86
|
+
const enterPart = (id) => {
|
|
87
|
+
if (!renderer)
|
|
88
|
+
return;
|
|
89
|
+
const next = SETUP_PART_OF[id];
|
|
90
|
+
if (next === part)
|
|
91
|
+
return;
|
|
92
|
+
const previous = ranPart;
|
|
93
|
+
part = next;
|
|
94
|
+
if (previous === undefined ||
|
|
95
|
+
next <= previous ||
|
|
96
|
+
rechecking ||
|
|
97
|
+
!journalSeen) {
|
|
98
|
+
renderer.heading(setupPartHeading(next, renderer.traits.unicode));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const progress = setupPartProgress(journalSeen, planned.scope);
|
|
102
|
+
const left = progress[previous].total - progress[previous].done;
|
|
103
|
+
renderer.heading(left
|
|
104
|
+
? `Part ${previous} has ${left === 1 ? "1 step" : `${left} steps`} left. Setup carries on with part ${next}.`
|
|
105
|
+
: `Part ${previous} done. ${SETUP_PARTS[previous].done}`);
|
|
106
|
+
renderer.tracker(setupTrackerRows(progress, { next }));
|
|
107
|
+
planPart(renderer, next, journalSeen);
|
|
108
|
+
renderer.blank();
|
|
109
|
+
};
|
|
84
110
|
const stop = () => {
|
|
85
111
|
if (active) {
|
|
86
112
|
if (renderer)
|
|
@@ -103,14 +129,16 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
103
129
|
}
|
|
104
130
|
signinShown = true;
|
|
105
131
|
if (reveal) {
|
|
106
|
-
|
|
107
|
-
renderer.
|
|
108
|
-
renderer.begin(4, title("signin"), "signing in…");
|
|
132
|
+
enterPart("signin");
|
|
133
|
+
renderer.begin(number("signin"), title("signin"), "signing in…");
|
|
109
134
|
active = true;
|
|
110
135
|
}
|
|
111
136
|
}
|
|
112
137
|
if (hidden(currentStep))
|
|
113
138
|
return;
|
|
139
|
+
// The sign-in's own wait line: the frame already shows the countdown and how to stop.
|
|
140
|
+
if (renderer && /^Waiting for you to approve…/.test(text))
|
|
141
|
+
return;
|
|
114
142
|
if (renderer &&
|
|
115
143
|
currentStep === "linear.adopt" &&
|
|
116
144
|
text.endsWith("already has every state and label"))
|
|
@@ -124,7 +152,7 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
124
152
|
}
|
|
125
153
|
if (currentStep === "capacity")
|
|
126
154
|
return;
|
|
127
|
-
renderer.detail(text);
|
|
155
|
+
renderer.detail(say(text));
|
|
128
156
|
return;
|
|
129
157
|
}
|
|
130
158
|
stop();
|
|
@@ -136,9 +164,9 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
136
164
|
if (hidden(currentStep))
|
|
137
165
|
return;
|
|
138
166
|
if (renderer && currentStep)
|
|
139
|
-
renderer.begin(
|
|
167
|
+
renderer.begin(number(currentStep), title(currentStep), text === ONBOARD_TITLES[currentStep] ? "checking…" : text);
|
|
140
168
|
else if (renderer)
|
|
141
|
-
renderer.line(text);
|
|
169
|
+
renderer.line(say(text));
|
|
142
170
|
else
|
|
143
171
|
spin.start(text);
|
|
144
172
|
active = true;
|
|
@@ -147,7 +175,7 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
147
175
|
const question = () => {
|
|
148
176
|
if (renderer && currentStep && !questionOpen) {
|
|
149
177
|
stop();
|
|
150
|
-
renderer.begin(
|
|
178
|
+
renderer.begin(number(currentStep), title(currentStep), "", "ask");
|
|
151
179
|
active = true;
|
|
152
180
|
questionOpen = true;
|
|
153
181
|
}
|
|
@@ -155,7 +183,7 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
155
183
|
const select = async (opts, ownFrame = false) => {
|
|
156
184
|
if (!renderer)
|
|
157
185
|
return prompts.select(opts);
|
|
158
|
-
const detached = ownFrame || !currentStep;
|
|
186
|
+
const detached = ownFrame || (!currentStep && !questionOpen);
|
|
159
187
|
if (detached) {
|
|
160
188
|
stop();
|
|
161
189
|
renderer.begin(0, "Your choice", "", "ask");
|
|
@@ -202,14 +230,15 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
202
230
|
renderer.heading(screen.heading);
|
|
203
231
|
if (screen.paused)
|
|
204
232
|
renderer.line("Your progress is saved.");
|
|
233
|
+
renderer.tracker(setupTrackerRows(setupPartProgress(journal, planned.scope), "end"));
|
|
205
234
|
if (screen.readinessCause)
|
|
206
|
-
renderer.line(screen.readinessCause);
|
|
235
|
+
renderer.line(say(screen.readinessCause));
|
|
207
236
|
if (screen.actions.length) {
|
|
208
237
|
renderer.line(`${screen.actions.length} ${screen.actions.length === 1 ? "thing needs" : "things need"} you:`);
|
|
209
|
-
screen.actions.forEach((action, i) => renderer.
|
|
238
|
+
screen.actions.forEach((action, i) => renderer.item(`${i + 1}. `, say(action.text)));
|
|
210
239
|
if (screen.more)
|
|
211
240
|
renderer.line(`and ${screen.more} more after these`);
|
|
212
|
-
const continuation = pendingContinuation(journal);
|
|
241
|
+
const continuation = pendingContinuation(journal, new Set(screen.actions.map((action) => action.id)));
|
|
213
242
|
if (continuation)
|
|
214
243
|
renderer.line(continuation);
|
|
215
244
|
}
|
|
@@ -227,6 +256,8 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
227
256
|
interactive,
|
|
228
257
|
handlesSignals: true,
|
|
229
258
|
plan(journal, identity, planOptions) {
|
|
259
|
+
planned = { scope: planOptions?.scope, runner: planOptions?.runner };
|
|
260
|
+
journalSeen = journal;
|
|
230
261
|
if (deps.consentGiven)
|
|
231
262
|
return;
|
|
232
263
|
machineScope = (planOptions?.scope ?? ONBOARD_STEPS).filter((id) => COMPUTER_CHECKS.some((check) => check === id));
|
|
@@ -235,32 +266,46 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
235
266
|
stop();
|
|
236
267
|
if (!introduced) {
|
|
237
268
|
if (renderer)
|
|
238
|
-
renderer.
|
|
269
|
+
renderer.brand("setup", deps.version);
|
|
239
270
|
else
|
|
240
271
|
prompts.intro("Catalyst setup", { output: streams.output });
|
|
241
272
|
introduced = true;
|
|
242
273
|
}
|
|
243
274
|
if (identity !== undefined)
|
|
244
275
|
for (const line of onboardIdentityLines(identity))
|
|
245
|
-
|
|
276
|
+
if (renderer)
|
|
277
|
+
renderer.line(line);
|
|
278
|
+
else
|
|
279
|
+
message(line);
|
|
280
|
+
// After sign-in the plan is asked about again. When it is the plan already on screen, the
|
|
281
|
+
// person sees who they are now and the question, not the header, tracker and plan twice.
|
|
282
|
+
const planKey = JSON.stringify([
|
|
283
|
+
planned.scope,
|
|
284
|
+
planned.runner,
|
|
285
|
+
planOptions?.localSync ?? journal.localSync === true,
|
|
286
|
+
]);
|
|
287
|
+
if (renderer && planKey === shownPlan)
|
|
288
|
+
return;
|
|
289
|
+
shownPlan = planKey;
|
|
246
290
|
if (renderer) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
291
|
+
// CTC-4680: what setup does and the three parts first, then only the first part's steps.
|
|
292
|
+
// Each later part lists its own steps when it starts.
|
|
293
|
+
const first = standalonePlan(journal, planned.scope, planned.runner)[0]?.part ?? 1;
|
|
294
|
+
renderer.blank();
|
|
295
|
+
renderer.line("Setup gets Catalyst working on your team's Linear tickets. It has three parts.");
|
|
296
|
+
renderer.tracker(setupTrackerRows(setupPartProgress(journal, planned.scope), {
|
|
297
|
+
plan: first,
|
|
298
|
+
}));
|
|
299
|
+
planPart(renderer, first, journal);
|
|
300
|
+
// Its steps follow under this heading; the first one does not print it again.
|
|
301
|
+
part = first;
|
|
257
302
|
renderer.line(standalonePlanNotes(planOptions?.localSync ?? journal.localSync === true));
|
|
258
303
|
return;
|
|
259
304
|
}
|
|
260
305
|
const steps = new Map(journal.steps.map((step) => [step.id, step]));
|
|
261
306
|
message(ONBOARD_STEPS.map((id) => `· ${ONBOARD_TITLES[id]}${steps.get(id)?.state === "done" ? " (recheck)" : ""}`).join("\n"));
|
|
262
307
|
message("Use cloud reads by default. Local sync is optional for SQL or sustained local reads.");
|
|
263
|
-
message("Setup
|
|
308
|
+
message("Setup reads your AI accounts without sending them a request.");
|
|
264
309
|
},
|
|
265
310
|
async confirmPlan(localSync, signin = "unavailable") {
|
|
266
311
|
if (deps.consentGiven || !interactive)
|
|
@@ -482,6 +527,36 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
482
527
|
}
|
|
483
528
|
return typeof answer === "string" ? answer : null;
|
|
484
529
|
},
|
|
530
|
+
async chooseFirstTicket(tickets, { teamKey, stage }) {
|
|
531
|
+
stop();
|
|
532
|
+
if (abort.signal.aborted)
|
|
533
|
+
return null;
|
|
534
|
+
const answer = await select({
|
|
535
|
+
...options,
|
|
536
|
+
message: `Which ticket should Catalyst start first? It moves to ${stage} in ${teamKey}.`,
|
|
537
|
+
initialValue: tickets[0]?.identifier ?? FIRST_TICKET_SAMPLE,
|
|
538
|
+
options: [
|
|
539
|
+
...tickets.map((ticket) => ({
|
|
540
|
+
value: ticket.identifier,
|
|
541
|
+
label: `${ticket.identifier} ${ticket.title}`,
|
|
542
|
+
...(ticket.estimate !== null
|
|
543
|
+
? { hint: `estimate ${ticket.estimate}` }
|
|
544
|
+
: {}),
|
|
545
|
+
})),
|
|
546
|
+
{
|
|
547
|
+
value: FIRST_TICKET_SAMPLE,
|
|
548
|
+
label: "Create a sample ticket",
|
|
549
|
+
hint: "documents how to run the tests; changes only CONTRIBUTING.md",
|
|
550
|
+
},
|
|
551
|
+
{ value: FIRST_TICKET_SKIP, label: "Skip for now" },
|
|
552
|
+
],
|
|
553
|
+
});
|
|
554
|
+
if (prompts.isCancel(answer)) {
|
|
555
|
+
abort.abort();
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
return typeof answer === "string" ? answer : null;
|
|
559
|
+
},
|
|
485
560
|
async chooseRunner() {
|
|
486
561
|
stop();
|
|
487
562
|
if (abort.signal.aborted)
|
|
@@ -511,15 +586,12 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
511
586
|
async retryTimedOut(id) {
|
|
512
587
|
if (abort.signal.aborted)
|
|
513
588
|
return false;
|
|
514
|
-
if (renderer
|
|
515
|
-
// The
|
|
516
|
-
|
|
517
|
-
renderer.
|
|
518
|
-
}
|
|
519
|
-
else if (renderer) {
|
|
520
|
-
renderer.begin(SETUP_NUMBERS[id] ?? 0, title(id), "the link timed out");
|
|
521
|
-
renderer.detail("The link timed out.");
|
|
589
|
+
if (renderer) {
|
|
590
|
+
// The question draws under this row, so the reason stays on screen while it is asked.
|
|
591
|
+
stop();
|
|
592
|
+
renderer.begin(number(id), title(id), "the link timed out", "ask");
|
|
522
593
|
active = true;
|
|
594
|
+
questionOpen = true;
|
|
523
595
|
}
|
|
524
596
|
else {
|
|
525
597
|
stop();
|
|
@@ -548,7 +620,7 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
548
620
|
if (state === "done")
|
|
549
621
|
stagedSigninApproved = true;
|
|
550
622
|
if (currentStep === "signin" && signinShown)
|
|
551
|
-
renderer.step(state === "done" ? "done" : state === "failed" ? "fail" : "act",
|
|
623
|
+
renderer.step(state === "done" ? "done" : state === "failed" ? "fail" : "act", number("signin"), title("signin"), state === "done"
|
|
552
624
|
? "approved"
|
|
553
625
|
: state === "failed"
|
|
554
626
|
? "could not verify this account"
|
|
@@ -560,11 +632,11 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
560
632
|
signinShown = false;
|
|
561
633
|
if (state !== "done") {
|
|
562
634
|
if (cause)
|
|
563
|
-
renderer.line(cause.charAt(0).toUpperCase() + cause.slice(1));
|
|
635
|
+
renderer.line(say(cause.charAt(0).toUpperCase() + cause.slice(1)));
|
|
564
636
|
renderer.heading(abort.signal.aborted ? "Setup paused" : "Setup is not ready yet");
|
|
565
637
|
if (!cause?.includes("Your saved connection was not changed."))
|
|
566
638
|
renderer.line("Your saved connection was not changed.");
|
|
567
|
-
renderer.outro("Next: run catalyst
|
|
639
|
+
renderer.outro("Next: run catalyst setup to sign in again.");
|
|
568
640
|
}
|
|
569
641
|
return true;
|
|
570
642
|
},
|
|
@@ -582,29 +654,17 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
582
654
|
if (!machineScope.length)
|
|
583
655
|
return;
|
|
584
656
|
if (machineChecks.size === 0 && !machineBlocked) {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
renderer.begin(1, "This computer", "checking…");
|
|
657
|
+
enterPart(id);
|
|
658
|
+
renderer.begin(number(id), "This computer", "checking…");
|
|
588
659
|
active = true;
|
|
589
660
|
}
|
|
590
661
|
return;
|
|
591
662
|
}
|
|
592
663
|
if (hidden(id))
|
|
593
664
|
return;
|
|
594
|
-
if (id === "projects"
|
|
665
|
+
if (id === "projects")
|
|
595
666
|
return;
|
|
596
|
-
|
|
597
|
-
["signin", "daemon", "housekeeping", "ready"].includes(id)
|
|
598
|
-
? "This computer"
|
|
599
|
-
: id.startsWith("linear.")
|
|
600
|
-
? "Linear"
|
|
601
|
-
: id.startsWith("github.")
|
|
602
|
-
? "GitHub"
|
|
603
|
-
: "Work";
|
|
604
|
-
if (next !== group) {
|
|
605
|
-
renderer.heading(next);
|
|
606
|
-
group = next;
|
|
607
|
-
}
|
|
667
|
+
enterPart(id);
|
|
608
668
|
start(ONBOARD_TITLES[id]);
|
|
609
669
|
return;
|
|
610
670
|
}
|
|
@@ -626,6 +686,9 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
626
686
|
start(ONBOARD_TITLES[id]);
|
|
627
687
|
},
|
|
628
688
|
stepEnd(step, journal) {
|
|
689
|
+
if (journal)
|
|
690
|
+
journalSeen = journal;
|
|
691
|
+
ranPart = SETUP_PART_OF[step.id];
|
|
629
692
|
if (renderer) {
|
|
630
693
|
if (standaloneComputer(step.id)) {
|
|
631
694
|
machineChecks.set(step.id, step);
|
|
@@ -656,20 +719,18 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
656
719
|
if ((step.id === "github.repos" || step.id === "settings") &&
|
|
657
720
|
step.state === "done")
|
|
658
721
|
return;
|
|
659
|
-
if (
|
|
660
|
-
journal?.steps.find((s) => s.id ===
|
|
722
|
+
if (step.id === "projects" &&
|
|
723
|
+
journal?.steps.find((s) => s.id === "github.repos")?.state !== "done")
|
|
661
724
|
return;
|
|
662
725
|
const view = setupStepView(step, journal);
|
|
663
|
-
if (hidden(step.id))
|
|
664
|
-
|
|
665
|
-
group = "This computer";
|
|
666
|
-
}
|
|
726
|
+
if (hidden(step.id))
|
|
727
|
+
enterPart(step.id);
|
|
667
728
|
renderer.step(view.mark, view.number, view.title, view.outcome);
|
|
668
729
|
const granted = deps.verbose ? onboardStepDetail(step) : undefined;
|
|
669
730
|
if (granted)
|
|
670
731
|
renderer.detail(granted);
|
|
671
732
|
if (deps.verbose && CONNECTION_REPAIR_REASONS.has(step.reason ?? ""))
|
|
672
|
-
renderer.detail(onboardReasonText(step, { baseUrl: deps.baseUrl?.(), journal }));
|
|
733
|
+
renderer.detail(say(onboardReasonText(step, { baseUrl: deps.baseUrl?.(), journal })));
|
|
673
734
|
if (view.mark === "fail")
|
|
674
735
|
renderer.detail(deps.logPath?.()
|
|
675
736
|
? "Check the full log for the cause, then try this step again."
|
|
@@ -697,6 +758,16 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
697
758
|
prompts.log.message(granted, { output: streams.output });
|
|
698
759
|
},
|
|
699
760
|
message,
|
|
761
|
+
note(text) {
|
|
762
|
+
if (hidden(currentStep))
|
|
763
|
+
return;
|
|
764
|
+
if (renderer)
|
|
765
|
+
renderer.detail(text);
|
|
766
|
+
else {
|
|
767
|
+
stop();
|
|
768
|
+
prompts.log.message(text, { output: streams.output });
|
|
769
|
+
}
|
|
770
|
+
},
|
|
700
771
|
async checkAgain(journal) {
|
|
701
772
|
if (!renderer ||
|
|
702
773
|
!interactive ||
|
|
@@ -725,7 +796,8 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
725
796
|
machineScope = COMPUTER_CHECKS.filter((id) => !stepSatisfied(journal.steps.find((step) => step.id === id)));
|
|
726
797
|
machineChecks.clear();
|
|
727
798
|
machineBlocked = false;
|
|
728
|
-
|
|
799
|
+
part = undefined;
|
|
800
|
+
rechecking = true;
|
|
729
801
|
renderer.heading("Checking again");
|
|
730
802
|
return true;
|
|
731
803
|
},
|
|
@@ -741,8 +813,8 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
741
813
|
renderer.line(`${ONBOARD_TITLES[only]} finished. Onboarding still has other steps.`);
|
|
742
814
|
else
|
|
743
815
|
for (const action of onboardNextActions(journal, deps.baseUrl?.(), only))
|
|
744
|
-
renderer.line(action);
|
|
745
|
-
renderer.outro("Next: run catalyst
|
|
816
|
+
renderer.line(say(action));
|
|
817
|
+
renderer.outro("Next: run catalyst setup");
|
|
746
818
|
return;
|
|
747
819
|
}
|
|
748
820
|
if (renderer) {
|
|
@@ -755,7 +827,7 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
755
827
|
renderer.line("Your progress is saved.");
|
|
756
828
|
}
|
|
757
829
|
summaryShown = false;
|
|
758
|
-
renderer.outro(screen.next);
|
|
830
|
+
renderer.outro(say(screen.next));
|
|
759
831
|
return;
|
|
760
832
|
}
|
|
761
833
|
stop();
|
|
@@ -779,10 +851,12 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
779
851
|
text = `${ONBOARD_TITLES[only]} finished. Onboarding still has other steps.\nresume: catalyst onboard`;
|
|
780
852
|
prompts.outro(text, { output: streams.output });
|
|
781
853
|
},
|
|
782
|
-
async wait(text, run) {
|
|
783
|
-
const browser = currentStep &&
|
|
784
|
-
|
|
785
|
-
|
|
854
|
+
async wait(text, run, page) {
|
|
855
|
+
const browser = currentStep && renderer && page
|
|
856
|
+
? page
|
|
857
|
+
: currentStep &&
|
|
858
|
+
renderer &&
|
|
859
|
+
setupBrowserInstruction(currentStep, deps.baseUrl?.(), currentStep !== "accounts" && browserOpened);
|
|
786
860
|
const signinWait = Boolean(renderer && currentStep === "signin" && signinShown);
|
|
787
861
|
const seconds = signinWait
|
|
788
862
|
? Math.ceil((deps.signinTimeoutMs ?? 600000) / 1000)
|
|
@@ -794,11 +868,9 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
794
868
|
};
|
|
795
869
|
if (renderer && browser && currentStep) {
|
|
796
870
|
stop();
|
|
797
|
-
renderer.begin(
|
|
871
|
+
renderer.begin(number(currentStep), title(currentStep), renderer.traits.unicode
|
|
798
872
|
? status()
|
|
799
873
|
: "waiting for you, up to 10 minutes");
|
|
800
|
-
if (browser.preparation)
|
|
801
|
-
renderer.detail(browser.preparation);
|
|
802
874
|
renderer.action(browser.instruction);
|
|
803
875
|
if (browser.url)
|
|
804
876
|
renderer.detail(renderer.link(browser.url));
|
|
@@ -881,6 +953,7 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
881
953
|
delete ui.chooseFirstRepository;
|
|
882
954
|
delete ui.reviewSettings;
|
|
883
955
|
delete ui.chooseRunner;
|
|
956
|
+
delete ui.chooseFirstTicket;
|
|
884
957
|
delete ui.retryTimedOut;
|
|
885
958
|
delete ui.confirmWorkflowAdoption;
|
|
886
959
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { loadConfig } from "./config.js";
|
|
2
|
+
import { loadContract } from "./contract.js";
|
|
3
|
+
import { selectedOnboardTeam } from "./onboard-existing.js";
|
|
4
|
+
import { valuesFacts } from "./ready-copy.js";
|
|
5
|
+
const waiting = (reason, evidence) => ({
|
|
6
|
+
state: "waiting",
|
|
7
|
+
reason,
|
|
8
|
+
...(evidence ? { evidence } : {}),
|
|
9
|
+
});
|
|
10
|
+
/** The selected team's `required_values` readiness check decides this step. It passes when the
|
|
11
|
+
* selected repositories declare no required value, or every one has a value. Nothing here reads,
|
|
12
|
+
* imports or prints a value: a missing one is named, with the page where it is set. A stale, absent
|
|
13
|
+
* or unknown check waits, so the step never claims values it could not see. */
|
|
14
|
+
export function onboardValuesAdapter() {
|
|
15
|
+
return {
|
|
16
|
+
check: async (ctx, journal, signal) => {
|
|
17
|
+
const cfg = loadConfig(ctx.home);
|
|
18
|
+
const teamId = selectedOnboardTeam(journal);
|
|
19
|
+
if (!cfg || !teamId)
|
|
20
|
+
return waiting("required_values_unverified");
|
|
21
|
+
let loaded;
|
|
22
|
+
try {
|
|
23
|
+
loaded = await loadContract(ctx, cfg, { refresh: true, signal });
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return waiting(signal?.aborted ? "interrupted" : "required_values_unverified");
|
|
27
|
+
}
|
|
28
|
+
if (loaded.source === "cache")
|
|
29
|
+
return waiting("required_values_unverified");
|
|
30
|
+
const readiness = loaded.doc.teams.find((team) => team.id === teamId)?.readiness;
|
|
31
|
+
const fresh = readiness?.checkedAt != null &&
|
|
32
|
+
readiness.expiresAt != null &&
|
|
33
|
+
readiness.expiresAt > ctx.now().getTime();
|
|
34
|
+
const check = fresh
|
|
35
|
+
? readiness.checks.find((row) => row.id === "required_values")
|
|
36
|
+
: undefined;
|
|
37
|
+
if (check?.state === "pass")
|
|
38
|
+
return { state: "done", evidence: { team: teamId } };
|
|
39
|
+
if (check?.state !== "fail")
|
|
40
|
+
return waiting("required_values_unverified");
|
|
41
|
+
return waiting("required_values_missing", {
|
|
42
|
+
team: teamId,
|
|
43
|
+
requiredValues: JSON.stringify(valuesFacts(check)),
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|