@catalyst-cloud/cli 0.14.6 → 0.14.8
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 +14 -0
- package/README.md +7 -5
- package/dist/args.js +68 -18
- package/dist/browser.js +37 -3
- package/dist/cli.js +58 -12
- package/dist/config.js +17 -5
- package/dist/consent-browser.js +58 -0
- package/dist/daemon-authority-lifetime.js +171 -0
- package/dist/daemon-authority.js +216 -0
- package/dist/daemon-cache.js +348 -0
- package/dist/daemon-store.js +370 -0
- package/dist/daemon-supervisor.js +460 -0
- package/dist/env/onboard-draft-store.js +250 -0
- package/dist/env/onboard-draft.js +33 -0
- package/dist/env/selected-import-writer.js +163 -0
- package/dist/env/settings-authority.js +205 -0
- package/dist/events-cloud-tail.js +146 -0
- package/dist/events-cloud.js +619 -0
- package/dist/events.js +186 -31
- package/dist/oauth.js +129 -34
- package/dist/onboard-accounts.js +259 -0
- package/dist/onboard-automation-management.js +15 -0
- package/dist/onboard-bootstrap.js +162 -0
- package/dist/onboard-capabilities.js +15 -7
- package/dist/onboard-capacity.js +226 -0
- package/dist/onboard-existing.js +106 -32
- package/dist/onboard-file-snapshot.js +45 -0
- package/dist/onboard-github.js +14 -3
- package/dist/onboard-login-candidate.js +261 -0
- package/dist/onboard-next.js +139 -0
- package/dist/onboard-personal.js +14 -3
- package/dist/onboard-projects.js +350 -0
- package/dist/onboard-repositories.js +146 -37
- package/dist/onboard-runtime.js +108 -13
- package/dist/onboard-settings-context.js +141 -0
- package/dist/onboard-settings-import.js +127 -0
- package/dist/onboard-settings.js +234 -0
- package/dist/onboard-ui.js +85 -59
- package/dist/onboard-workflow.js +316 -0
- package/dist/onboard-workspace.js +14 -3
- package/dist/onboard.js +422 -39
- package/dist/owned-fetch.js +182 -0
- package/dist/pagination.js +13 -1
- package/dist/query.js +104 -31
- package/dist/ready.js +143 -35
- package/dist/replica.js +11 -4
- package/dist/repository-id.js +5 -0
- package/dist/sdk.js +33 -0
- package/dist/watch.js +2 -2
- package/package.json +3 -2
- package/skills/catalyst-github/SKILL.md +4 -2
- package/skills/catalyst-github/references/is-it-mergeable.md +1 -1
- package/skills/catalyst-github/references/local-replica.md +78 -0
- package/skills/catalyst-github/references/reading-from-the-cloud.md +24 -0
- package/skills/catalyst-github/references/what-a-pr-accumulates.md +1 -1
- package/skills/catalyst-github/scripts/is-it-mergeable.mjs +210 -45
- package/skills/catalyst-github/scripts/read-pr.mjs +51 -15
- package/skills/catalyst-linear/SKILL.md +5 -3
- package/skills/catalyst-linear/references/local-replica.md +91 -0
- package/skills/catalyst-linear/references/reading-a-ticket.md +3 -3
- package/skills/catalyst-linear/references/reading-from-the-cloud.md +38 -0
- package/skills/catalyst-linear/scripts/read-ticket.mjs +37 -12
- package/skills/catalyst-onboard/SKILL.md +6 -4
- package/skills/catalyst-onboard/references/local-replica.md +40 -0
- package/skills/catalyst-onboard/references/local-sync.md +8 -4
- package/skills/catalyst-onboard/scripts/local-sync.mjs +2 -2
- package/skills/catalyst-onboard/scripts/where-am-i.mjs +1 -1
- package/skills/run-this-project/SKILL.md +1 -1
- 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 +4 -2
- package/skills/whats-happening/references/local-replica.md +51 -0
- package/skills/whats-happening/references/reading-from-the-cloud.md +21 -0
- package/skills/whats-happening/references/status-reply.md +1 -1
- package/skills/whats-happening/scripts/snapshot.mjs +104 -26
- package/vendor/settings/index.d.ts +4 -0
- package/vendor/settings/index.js +2937 -0
- package/vendor/settings/provenance.json +148 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
2
|
+
import { storeOnboardDraft } from "./env/onboard-draft-store.js";
|
|
3
|
+
import { isAbsolute, resolve } from "node:path";
|
|
4
|
+
import { validateFullSettings } from "../vendor/settings/index.js";
|
|
5
|
+
import { draftOnboardSettings, } from "./env/onboard-draft.js";
|
|
6
|
+
import { onboardSettingsAuthorityPorts } from "./onboard-settings-context.js";
|
|
7
|
+
import { selectedOnboardRepositories, } from "./onboard-repositories.js";
|
|
8
|
+
import { normalizeBaseUrl } from "./config.js";
|
|
9
|
+
import { selectedOnboardTeam } from "./onboard-existing.js";
|
|
10
|
+
const waiting = (reason, evidence) => ({
|
|
11
|
+
state: "waiting",
|
|
12
|
+
reason,
|
|
13
|
+
...(evidence ? { evidence } : {}),
|
|
14
|
+
});
|
|
15
|
+
const contextKey = (value) => JSON.stringify([
|
|
16
|
+
value.accountId,
|
|
17
|
+
value.personId,
|
|
18
|
+
value.baseUrl,
|
|
19
|
+
value.role,
|
|
20
|
+
value.teamId,
|
|
21
|
+
value.teamKey,
|
|
22
|
+
value.repoId,
|
|
23
|
+
value.repoName,
|
|
24
|
+
value.repoRoot,
|
|
25
|
+
]);
|
|
26
|
+
const safeLabel = (text) => text.replace(/[\u0000-\u001f\u007f-\u009f]/g, "").slice(0, 240);
|
|
27
|
+
async function boundedRead(work, external, timeoutMs = 30_000) {
|
|
28
|
+
const owned = new AbortController();
|
|
29
|
+
const signal = external
|
|
30
|
+
? AbortSignal.any([external, owned.signal])
|
|
31
|
+
: owned.signal;
|
|
32
|
+
let timer;
|
|
33
|
+
let remove = () => { };
|
|
34
|
+
try {
|
|
35
|
+
return await new Promise((resolve) => {
|
|
36
|
+
const stopped = () => resolve(null);
|
|
37
|
+
if (signal.aborted) {
|
|
38
|
+
stopped();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
signal.addEventListener("abort", stopped, { once: true });
|
|
42
|
+
remove = () => signal.removeEventListener("abort", stopped);
|
|
43
|
+
timer = setTimeout(() => owned.abort(), timeoutMs);
|
|
44
|
+
Promise.resolve()
|
|
45
|
+
.then(() => work(signal))
|
|
46
|
+
.then((result) => resolve(signal.aborted ? null : result), () => resolve(null));
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
if (timer)
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
remove();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Q4 drafts are local review artifacts. A full local validator is not declaration approval;
|
|
56
|
+
* neither a kept draft nor a valid existing file marks this required step complete. */
|
|
57
|
+
export function onboardSettingsAdapter(hooks = {}) {
|
|
58
|
+
const storeTimeoutMs = hooks.storeTimeoutMs ?? 30_000;
|
|
59
|
+
if (!Number.isSafeInteger(storeTimeoutMs) ||
|
|
60
|
+
storeTimeoutMs < 1 ||
|
|
61
|
+
storeTimeoutMs > 30_000)
|
|
62
|
+
throw new Error("settings_storage_timeout_invalid");
|
|
63
|
+
const observe = async (ctx, journal, signal) => {
|
|
64
|
+
const repositories = selectedOnboardRepositories(journal);
|
|
65
|
+
const summaries = [];
|
|
66
|
+
const candidates = [];
|
|
67
|
+
for (const repository of repositories) {
|
|
68
|
+
if (signal?.aborted)
|
|
69
|
+
return null;
|
|
70
|
+
const summary = {
|
|
71
|
+
repository: `${repository.owner}/${repository.name}`,
|
|
72
|
+
state: "unavailable",
|
|
73
|
+
variableNames: [],
|
|
74
|
+
secretNames: [],
|
|
75
|
+
sources: [],
|
|
76
|
+
};
|
|
77
|
+
summaries.push(summary);
|
|
78
|
+
try {
|
|
79
|
+
const requested = hooks.repositoryRoot
|
|
80
|
+
? hooks.repositoryRoot({ ...repository })
|
|
81
|
+
: process.cwd();
|
|
82
|
+
if (!requested ||
|
|
83
|
+
!isAbsolute(requested) ||
|
|
84
|
+
(await realpath(requested)) !== resolve(requested) ||
|
|
85
|
+
signal?.aborted)
|
|
86
|
+
continue;
|
|
87
|
+
const ports = (hooks.authorityPorts ??
|
|
88
|
+
((c, j, r, root) => onboardSettingsAuthorityPorts({
|
|
89
|
+
ctx: c,
|
|
90
|
+
journal: j,
|
|
91
|
+
repository: r,
|
|
92
|
+
repoRoot: root,
|
|
93
|
+
})))(ctx, journal, repository, requested);
|
|
94
|
+
const before = await ports.readContext(signal);
|
|
95
|
+
if (!before ||
|
|
96
|
+
before.accountId !== (journal.account ?? journal.tenant) ||
|
|
97
|
+
before.personId !== journal.membershipId ||
|
|
98
|
+
!journal.baseUrl ||
|
|
99
|
+
before.baseUrl !== normalizeBaseUrl(journal.baseUrl) ||
|
|
100
|
+
!["owner", "admin"].includes(before.role) ||
|
|
101
|
+
before.teamId !== selectedOnboardTeam(journal) ||
|
|
102
|
+
before.teamId !== repository.teamId ||
|
|
103
|
+
!/^[A-Z][A-Z0-9]{0,15}$/.test(before.teamKey) ||
|
|
104
|
+
before.repoId !== repository.repoId ||
|
|
105
|
+
before.repoName !== summary.repository.toLowerCase() ||
|
|
106
|
+
before.repoRoot !== resolve(requested) ||
|
|
107
|
+
signal?.aborted)
|
|
108
|
+
continue;
|
|
109
|
+
const binding = contextKey(before);
|
|
110
|
+
const existing = await ports.readSettings(requested, signal);
|
|
111
|
+
if (existing !== null) {
|
|
112
|
+
const checked = validateFullSettings(existing);
|
|
113
|
+
const after = await ports.readContext(signal);
|
|
114
|
+
if (!checked.ok ||
|
|
115
|
+
checked.linearTeam !== before.teamKey ||
|
|
116
|
+
!after ||
|
|
117
|
+
contextKey(after) !== binding ||
|
|
118
|
+
signal?.aborted)
|
|
119
|
+
continue;
|
|
120
|
+
Object.assign(summary, {
|
|
121
|
+
state: "existing",
|
|
122
|
+
variableNames: checked.variableNames,
|
|
123
|
+
secretNames: checked.secretNames,
|
|
124
|
+
sources: [".catalyst/catalyst.toml"],
|
|
125
|
+
});
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const draft = (hooks.draft ?? draftOnboardSettings)(requested, before.teamKey);
|
|
129
|
+
if (draft.state !== "draft")
|
|
130
|
+
continue;
|
|
131
|
+
const checked = validateFullSettings(draft.toml);
|
|
132
|
+
const after = await ports.readContext(signal);
|
|
133
|
+
if (!checked.ok ||
|
|
134
|
+
checked.linearTeam !== before.teamKey ||
|
|
135
|
+
!after ||
|
|
136
|
+
contextKey(after) !== binding ||
|
|
137
|
+
signal?.aborted)
|
|
138
|
+
continue;
|
|
139
|
+
Object.assign(summary, {
|
|
140
|
+
state: "draft",
|
|
141
|
+
variableNames: checked.variableNames,
|
|
142
|
+
secretNames: checked.secretNames,
|
|
143
|
+
sources: draft.sources.map(safeLabel),
|
|
144
|
+
});
|
|
145
|
+
candidates.push({
|
|
146
|
+
repository: { ...repository },
|
|
147
|
+
context: { ...before },
|
|
148
|
+
ports,
|
|
149
|
+
draft,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
/* One unavailable checkout cannot approve the other repositories. */
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return { summaries, candidates };
|
|
157
|
+
};
|
|
158
|
+
const bounded = (ctx, journal, external) => boundedRead((signal) => observe(ctx, journal, signal), external);
|
|
159
|
+
return {
|
|
160
|
+
check: async (ctx, journal, signal) => {
|
|
161
|
+
const read = await bounded(ctx, journal, signal);
|
|
162
|
+
if (!read?.summaries.length)
|
|
163
|
+
return waiting("settings_checkout_unverified");
|
|
164
|
+
if (read.summaries.some((summary) => summary.state === "unavailable"))
|
|
165
|
+
return waiting("settings_checkout_unverified");
|
|
166
|
+
return read.candidates.length
|
|
167
|
+
? { state: "pending" }
|
|
168
|
+
: waiting("settings_approval_unverified");
|
|
169
|
+
},
|
|
170
|
+
act: async (ctx, journal, signal) => {
|
|
171
|
+
const read = await bounded(ctx, journal, signal);
|
|
172
|
+
if (!read?.summaries.length || signal?.aborted)
|
|
173
|
+
return waiting("settings_checkout_unverified");
|
|
174
|
+
for (const summary of read.summaries) {
|
|
175
|
+
hooks.message?.(`Settings for ${summary.repository}\n ${summary.state === "unavailable" ? "Local checkout or settings could not be verified." : `Full settings schema validation passed locally (${summary.state === "draft" ? "new draft; private copy pending" : "existing repository file; kept unchanged"}).\n Variables: ${summary.variableNames.join(", ") || "none"}\n Secrets: ${summary.secretNames.join(", ") || "none"}\n Sources: ${summary.sources.join(", ") || "none"}`}`);
|
|
176
|
+
}
|
|
177
|
+
const choice = hooks.review
|
|
178
|
+
? await boundedRead(async () => hooks.review(read.summaries.map((row) => ({
|
|
179
|
+
...row,
|
|
180
|
+
variableNames: [...row.variableNames],
|
|
181
|
+
secretNames: [...row.secretNames],
|
|
182
|
+
sources: [...row.sources],
|
|
183
|
+
}))), signal, 600_000)
|
|
184
|
+
: "keep";
|
|
185
|
+
if (choice === null && !signal?.aborted)
|
|
186
|
+
return waiting("settings_review_timeout");
|
|
187
|
+
if (choice !== "keep" || signal?.aborted)
|
|
188
|
+
return waiting("interrupted");
|
|
189
|
+
if (read.summaries.some((summary) => summary.state === "unavailable"))
|
|
190
|
+
return waiting("settings_checkout_unverified");
|
|
191
|
+
let stored = 0;
|
|
192
|
+
for (const candidate of read.candidates) {
|
|
193
|
+
const current = await boundedRead((owned) => candidate.ports.readContext(owned), signal);
|
|
194
|
+
if (!current ||
|
|
195
|
+
contextKey(current) !== contextKey(candidate.context) ||
|
|
196
|
+
signal?.aborted)
|
|
197
|
+
return waiting("settings_checkout_unverified", { count: stored });
|
|
198
|
+
const ownedStore = new AbortController();
|
|
199
|
+
const storeSignal = signal
|
|
200
|
+
? AbortSignal.any([signal, ownedStore.signal])
|
|
201
|
+
: ownedStore.signal;
|
|
202
|
+
const timer = setTimeout(() => ownedStore.abort(), storeTimeoutMs);
|
|
203
|
+
let result;
|
|
204
|
+
try {
|
|
205
|
+
// Do not race this promise. The writer settles all IO/owned cleanup before the engine
|
|
206
|
+
// may release its receipt lock, including after cancellation or the cooperative budget.
|
|
207
|
+
result = await (hooks.storeDraft ?? storeOnboardDraft)({
|
|
208
|
+
home: ctx.home,
|
|
209
|
+
env: { ...ctx.env },
|
|
210
|
+
runId: journal.runId,
|
|
211
|
+
repoId: candidate.repository.repoId,
|
|
212
|
+
toml: candidate.draft.toml,
|
|
213
|
+
signal: storeSignal,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
result = { state: "rejected" };
|
|
218
|
+
}
|
|
219
|
+
finally {
|
|
220
|
+
clearTimeout(timer);
|
|
221
|
+
}
|
|
222
|
+
if (storeSignal.aborted)
|
|
223
|
+
return waiting(signal?.aborted ? "interrupted" : "settings_draft_storage_timeout", { count: stored });
|
|
224
|
+
if (result.state !== "stored" || signal?.aborted)
|
|
225
|
+
return waiting("settings_draft_storage_unavailable", {
|
|
226
|
+
count: stored,
|
|
227
|
+
});
|
|
228
|
+
stored++;
|
|
229
|
+
hooks.message?.(`Kept a private settings draft copy for ${candidate.repository.owner}/${candidate.repository.name}: ${safeLabel(result.path)}`);
|
|
230
|
+
}
|
|
231
|
+
return waiting("settings_approval_unverified", { count: stored });
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
package/dist/onboard-ui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createOnboardProgress, } from "./onboard-progress.js";
|
|
2
|
-
import { ONBOARD_STEPS, ONBOARD_TITLES, } from "./onboard.js";
|
|
2
|
+
import { ONBOARD_STEPS, ONBOARD_TITLES, onboardIdentityLines, onboardNextActions, onboardReadyForWork, onboardStepAction, } from "./onboard.js";
|
|
3
3
|
export function shouldUseOnboardUi(args, stdoutTty) {
|
|
4
4
|
return (stdoutTty &&
|
|
5
5
|
!args.json &&
|
|
@@ -38,29 +38,47 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
38
38
|
};
|
|
39
39
|
return {
|
|
40
40
|
signal: abort.signal,
|
|
41
|
-
plan(journal) {
|
|
41
|
+
plan(journal, identity) {
|
|
42
42
|
stop();
|
|
43
43
|
if (!introduced) {
|
|
44
44
|
prompts.intro("Catalyst setup", { output: streams.output });
|
|
45
45
|
introduced = true;
|
|
46
46
|
}
|
|
47
|
+
if (identity !== undefined)
|
|
48
|
+
for (const line of onboardIdentityLines(identity))
|
|
49
|
+
message(line);
|
|
47
50
|
const steps = new Map(journal.steps.map((step) => [step.id, step]));
|
|
48
51
|
message(ONBOARD_STEPS.map((id) => `· ${ONBOARD_TITLES[id]}${steps.get(id)?.state === "done" ? " (recheck)" : ""}`).join("\n"));
|
|
49
|
-
message("Use cloud reads by default. Local sync is optional for SQL
|
|
52
|
+
message("Use cloud reads by default. Local sync is optional for SQL or sustained local reads.");
|
|
53
|
+
message("Setup may check one stored Claude account using a one-token provider request. This may use Claude quota. It does not refresh Codex credentials.");
|
|
50
54
|
},
|
|
51
|
-
async confirmPlan(localSync) {
|
|
55
|
+
async confirmPlan(localSync, signin = "unavailable") {
|
|
52
56
|
stop();
|
|
53
57
|
const answer = await prompts.select({
|
|
54
58
|
...options,
|
|
55
59
|
message: "Continue with this plan?",
|
|
56
|
-
initialValue: localSync ? "local" : "cloud",
|
|
60
|
+
initialValue: signin === "required" ? "signin" : localSync ? "local" : "cloud",
|
|
57
61
|
options: [
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
...(signin === "required"
|
|
63
|
+
? []
|
|
64
|
+
: [
|
|
65
|
+
{
|
|
66
|
+
value: "cloud",
|
|
67
|
+
label: "Continue using cloud reads",
|
|
68
|
+
hint: "default",
|
|
69
|
+
},
|
|
70
|
+
{ value: "local", label: "Continue and set up local sync" },
|
|
71
|
+
]),
|
|
72
|
+
...(signin === "unavailable"
|
|
73
|
+
? []
|
|
74
|
+
: [
|
|
75
|
+
{
|
|
76
|
+
value: "signin",
|
|
77
|
+
label: signin === "saved"
|
|
78
|
+
? "Sign in again before continuing"
|
|
79
|
+
: "Sign in and review this plan",
|
|
80
|
+
},
|
|
81
|
+
]),
|
|
64
82
|
{ value: "stop", label: "Stop without changes" },
|
|
65
83
|
],
|
|
66
84
|
});
|
|
@@ -71,6 +89,7 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
71
89
|
return {
|
|
72
90
|
proceed: answer === "cloud" || answer === "local",
|
|
73
91
|
localSync: answer === "local",
|
|
92
|
+
...(answer === "signin" ? { signin: true } : {}),
|
|
74
93
|
};
|
|
75
94
|
},
|
|
76
95
|
async chooseTeam(teams) {
|
|
@@ -115,6 +134,48 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
115
134
|
},
|
|
116
135
|
}
|
|
117
136
|
: {}),
|
|
137
|
+
async reviewSettings(summaries) {
|
|
138
|
+
stop();
|
|
139
|
+
if (!summaries.length || abort.signal.aborted)
|
|
140
|
+
return "cancel";
|
|
141
|
+
const answer = await prompts.select({
|
|
142
|
+
...options,
|
|
143
|
+
message: "Review settings for all selected repositories. Keep private copies of new drafts for review?",
|
|
144
|
+
initialValue: "keep",
|
|
145
|
+
options: [
|
|
146
|
+
{
|
|
147
|
+
value: "keep",
|
|
148
|
+
label: "Keep private draft copies",
|
|
149
|
+
hint: "default; repository files stay unchanged; approval and value import stay pending",
|
|
150
|
+
},
|
|
151
|
+
{ value: "stop", label: "Stop without keeping new copies" },
|
|
152
|
+
],
|
|
153
|
+
});
|
|
154
|
+
if (prompts.isCancel(answer) || answer === "stop") {
|
|
155
|
+
abort.abort();
|
|
156
|
+
return "cancel";
|
|
157
|
+
}
|
|
158
|
+
return answer === "keep" ? "keep" : "cancel";
|
|
159
|
+
},
|
|
160
|
+
async chooseFirstRepository(repositories) {
|
|
161
|
+
stop();
|
|
162
|
+
if (!repositories.length || abort.signal.aborted)
|
|
163
|
+
return null;
|
|
164
|
+
const answer = await prompts.select({
|
|
165
|
+
...options,
|
|
166
|
+
message: "Which repository should start this project?",
|
|
167
|
+
initialValue: `${repositories[0].owner}/${repositories[0].name}`,
|
|
168
|
+
options: repositories.map((row) => ({
|
|
169
|
+
value: `${row.owner}/${row.name}`,
|
|
170
|
+
label: `${row.owner}/${row.name}`,
|
|
171
|
+
})),
|
|
172
|
+
});
|
|
173
|
+
if (prompts.isCancel(answer)) {
|
|
174
|
+
abort.abort();
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
return typeof answer === "string" ? answer : null;
|
|
178
|
+
},
|
|
118
179
|
stepStart(id) {
|
|
119
180
|
const next = ["machine", "cli", "skills", "legacy"].includes(id)
|
|
120
181
|
? "This computer"
|
|
@@ -133,54 +194,9 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
133
194
|
}
|
|
134
195
|
start(ONBOARD_TITLES[id]);
|
|
135
196
|
},
|
|
136
|
-
stepEnd(step) {
|
|
197
|
+
stepEnd(step, journal) {
|
|
137
198
|
stop();
|
|
138
|
-
const
|
|
139
|
-
personal_consent_handoff: "The browser approval link could not be verified. Run catalyst onboard to try again.",
|
|
140
|
-
personal_identity_refused: "Your current login no longer matches this setup. Resume with the original workspace and person.",
|
|
141
|
-
personal_login_refresh_required: "Renew your login with catalyst login, then run catalyst onboard to resume.",
|
|
142
|
-
personal_status_unavailable: "Your personal connection could not be checked. Run catalyst onboard to try again.",
|
|
143
|
-
personal_browser_unavailable: "The browser could not open. Run catalyst onboard to try again.",
|
|
144
|
-
cloud_capability_unavailable: "This setup step is not available on this server yet. Use the web app link shown above, then resume after the server update.",
|
|
145
|
-
onboarding_capability_unavailable: "The server's setup capabilities could not be checked. Run catalyst onboard to try again.",
|
|
146
|
-
onboarding_capability_identity_unverified: "The server's setup capabilities belong to another login or workspace. Sign in to the original workspace to resume.",
|
|
147
|
-
onboarding_capability_login_refresh_required: "Your login needs a refresh before setup capabilities can be checked. Run catalyst login, then catalyst onboard.",
|
|
148
|
-
workspace_consent_refused: "The server did not accept this login for Linear workspace setup. Sign in again or ask your workspace administrator.",
|
|
149
|
-
github_installation_status_unavailable: "Your GitHub App installation could not be checked. Run catalyst onboard to try again.",
|
|
150
|
-
github_installation_status_shape: "The server returned a GitHub installation result that could not be verified.",
|
|
151
|
-
github_installation_consent_handoff: "The GitHub installation approval link could not be verified. Run catalyst onboard to try again.",
|
|
152
|
-
github_installation_consent_refused: "The server did not accept this login for GitHub App setup. Sign in again or ask your workspace administrator.",
|
|
153
|
-
github_installation_identity_refused: "GitHub setup belongs to another login or workspace. Sign in to the original workspace to resume.",
|
|
154
|
-
github_installation_admin_required: "A workspace owner or administrator approves the GitHub App installation.",
|
|
155
|
-
github_installation_login_refresh_required: "Your login needs a refresh. Run catalyst onboard to resume.",
|
|
156
|
-
github_installation_browser_unavailable: "The GitHub App approval page could not be opened. Use your workspace's Connections page, then resume.",
|
|
157
|
-
step_not_available_in_this_release: "This setup step is not available yet.",
|
|
158
|
-
prerequisite_not_ready: "Waiting for an earlier setup step.",
|
|
159
|
-
local_sync_not_selected: "Using cloud reads. Local sync was not selected.",
|
|
160
|
-
local_sync_capability_unavailable: "Local sync was selected but could not be verified.",
|
|
161
|
-
member_scope: "Your workspace administrator handles this step.",
|
|
162
|
-
onboarding_checks_pending: "Some required checks are still unverified.",
|
|
163
|
-
interrupted: "Setup paused. Run the same command to resume.",
|
|
164
|
-
signin_timeout: "Sign-in timed out. Run catalyst onboard to try again.",
|
|
165
|
-
linear_workspace_unverified: "Your Linear workspace connection could not be verified.",
|
|
166
|
-
team_inventory_empty: "No existing Linear teams could be verified.",
|
|
167
|
-
team_inventory_shape: "The cloud returned a team list that could not be verified.",
|
|
168
|
-
team_read_unavailable: "Your existing Linear teams could not be read. Run catalyst onboard to try again.",
|
|
169
|
-
team_read_login_refresh_required: "Your login needs a refresh. Run catalyst onboard to resume.",
|
|
170
|
-
team_choice_required: "Choose an existing team with catalyst onboard --team <team ID or key>.",
|
|
171
|
-
team_selection_unverified: "Your selected Linear team could not be verified. Run catalyst onboard --team <team ID or key> to choose again.",
|
|
172
|
-
repository_choice_required: "Choose repositories with catalyst onboard --repo <owner/name>. Repeat --repo to choose more than one.",
|
|
173
|
-
repository_inventory_empty: "No accessible repositories are registered to this Linear team yet.",
|
|
174
|
-
repository_read_unavailable: "Your repository list could not be read. Run catalyst onboard to try again.",
|
|
175
|
-
repository_inventory_shape: "The cloud returned a repository list that could not be verified.",
|
|
176
|
-
repository_contract_unavailable: "Current repository IDs could not be checked. Run catalyst onboard to try again.",
|
|
177
|
-
repository_contract_unverified: "The cloud returned repository IDs that could not be verified for this workspace.",
|
|
178
|
-
repository_id_unverified: "A repository's current ID could not be verified. Keep your selection and try again.",
|
|
179
|
-
repository_binding_ambiguous: "A repository's Linear team binding is ambiguous. Your administrator needs to check it.",
|
|
180
|
-
repository_identity_unverified: "Sign in to the original workspace to choose repositories.",
|
|
181
|
-
repository_selection_unverified: "Your selected repositories could not be verified. Run catalyst onboard --repo <owner/name> to choose again.",
|
|
182
|
-
};
|
|
183
|
-
const text = `${ONBOARD_TITLES[step.id]}${step.reason ? `: ${reasons[step.reason] ?? step.reason.replaceAll("_", " ")}` : ""}`;
|
|
199
|
+
const text = `${ONBOARD_TITLES[step.id]}${step.reason ? `: ${onboardStepAction(journal, step, deps.baseUrl?.())}` : ""}`;
|
|
184
200
|
const kind = step.state === "done"
|
|
185
201
|
? "info"
|
|
186
202
|
: step.state === "failed"
|
|
@@ -195,12 +211,22 @@ export function createClackOnboardUi(prompts, streams, deps = {}) {
|
|
|
195
211
|
message,
|
|
196
212
|
finish(journal, only) {
|
|
197
213
|
stop();
|
|
198
|
-
let text =
|
|
214
|
+
let text = [
|
|
215
|
+
"Setup still needs these steps:",
|
|
216
|
+
...onboardNextActions(journal, deps.baseUrl?.(), only),
|
|
217
|
+
"resume: catalyst onboard",
|
|
218
|
+
].join("\n");
|
|
199
219
|
if (abort.signal.aborted)
|
|
200
220
|
text =
|
|
201
221
|
"Setup paused. Your progress is saved.\nresume: catalyst onboard";
|
|
202
222
|
else if (journal.complete && journal.exit === 0 && !only)
|
|
203
223
|
text = "Onboarding complete.";
|
|
224
|
+
else if (onboardReadyForWork(journal, only))
|
|
225
|
+
text = [
|
|
226
|
+
"Ready for work.",
|
|
227
|
+
"Next, when you want:",
|
|
228
|
+
...onboardNextActions(journal, deps.baseUrl?.()),
|
|
229
|
+
].join("\n");
|
|
204
230
|
else if (only && journal.exit === 0)
|
|
205
231
|
text = `${ONBOARD_TITLES[only]} finished. Onboarding still has other steps.\nresume: catalyst onboard`;
|
|
206
232
|
prompts.outro(text, { output: streams.output });
|