@solarains/va-cli 0.1.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/LICENSE +21 -0
- package/README.md +132 -0
- package/dist/cli/command-types.js +2 -0
- package/dist/cli/help-copy.js +97 -0
- package/dist/cli/help.js +29 -0
- package/dist/cli/root-command.js +24 -0
- package/dist/cli/run-cli.js +107 -0
- package/dist/commands/assets/assets-command.js +10 -0
- package/dist/commands/assets/list-command.js +52 -0
- package/dist/commands/auth/auth-command.js +11 -0
- package/dist/commands/auth/login-command.js +127 -0
- package/dist/commands/auth/logout-command.js +57 -0
- package/dist/commands/doctor/doctor-command.js +33 -0
- package/dist/commands/init/init-command.js +19 -0
- package/dist/commands/intelligence/intelligence-command.js +10 -0
- package/dist/commands/intelligence/query-command.js +109 -0
- package/dist/commands/reports/get-command.js +69 -0
- package/dist/commands/reports/list-command.js +33 -0
- package/dist/commands/reports/reports-command.js +11 -0
- package/dist/commands/usage/usage-command.js +27 -0
- package/dist/config/locale.js +30 -0
- package/dist/config/runtime-config.js +64 -0
- package/dist/features/assets/assets-api-client.js +18 -0
- package/dist/features/assets/assets-output.js +28 -0
- package/dist/features/auth/auth-api-client.js +60 -0
- package/dist/features/auth/authenticated-api-client.js +142 -0
- package/dist/features/auth/browser-login.js +191 -0
- package/dist/features/auth/installation-state.js +65 -0
- package/dist/features/auth/loopback-callback-page.js +231 -0
- package/dist/features/daily-reports/daily-reports-api-client.js +22 -0
- package/dist/features/daily-reports/daily-reports-output.js +54 -0
- package/dist/features/init/detect-targets.js +57 -0
- package/dist/features/init/init-copy.js +348 -0
- package/dist/features/init/init-flow.js +661 -0
- package/dist/features/init/installer.js +122 -0
- package/dist/features/init/manifest.js +29 -0
- package/dist/features/init/presentation.js +147 -0
- package/dist/features/init/prompt.js +135 -0
- package/dist/features/init/target-registry.js +45 -0
- package/dist/features/init/templates.js +84 -0
- package/dist/features/init/types.js +2 -0
- package/dist/features/intelligence/intelligence-api-client.js +18 -0
- package/dist/features/intelligence/intelligence-output.js +36 -0
- package/dist/features/intelligence/intelligence-query-state.js +20 -0
- package/dist/features/usage/usage-api-client.js +7 -0
- package/dist/features/usage/usage-output.js +52 -0
- package/dist/main.js +7 -0
- package/dist/shared/argv.js +65 -0
- package/dist/shared/logger.js +32 -0
- package/dist/shared/output.js +22 -0
- package/dist/state/paths.js +32 -0
- package/dist/state/stores/file-json-store.js +29 -0
- package/dist/state/stores/installation-store.js +20 -0
- package/dist/state/stores/token-store.js +20 -0
- package/package.json +19 -0
- package/skills/visionalpha-operator/SKILL.md +38 -0
- package/skills/visionalpha-operator/agents/openai.yaml +4 -0
- package/skills/visionalpha-operator/references/asset-intelligence.md +35 -0
- package/skills/visionalpha-operator/references/assets.md +29 -0
- package/skills/visionalpha-operator/references/auth-recovery.md +26 -0
- package/skills/visionalpha-operator/references/daily-reports.md +30 -0
- package/skills/visionalpha-operator/references/usage-summary.md +24 -0
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolveInitOptions = resolveInitOptions;
|
|
7
|
+
exports.runInitFlow = runInitFlow;
|
|
8
|
+
const node_os_1 = require("node:os");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const locale_1 = require("../../config/locale");
|
|
11
|
+
const runtime_config_1 = require("../../config/runtime-config");
|
|
12
|
+
const argv_1 = require("../../shared/argv");
|
|
13
|
+
const logger_1 = require("../../shared/logger");
|
|
14
|
+
const ora_1 = __importDefault(require("ora"));
|
|
15
|
+
const detect_targets_1 = require("./detect-targets");
|
|
16
|
+
const init_copy_1 = require("./init-copy");
|
|
17
|
+
const installer_1 = require("./installer");
|
|
18
|
+
const presentation_1 = require("./presentation");
|
|
19
|
+
const prompt_1 = require("./prompt");
|
|
20
|
+
const target_registry_1 = require("./target-registry");
|
|
21
|
+
class CapturedStepLogger extends logger_1.Logger {
|
|
22
|
+
onLine;
|
|
23
|
+
lineCount = 0;
|
|
24
|
+
constructor(debugEnabled, onLine) {
|
|
25
|
+
super(debugEnabled);
|
|
26
|
+
this.onLine = onLine;
|
|
27
|
+
}
|
|
28
|
+
plain(message) {
|
|
29
|
+
const lines = message.split('\n');
|
|
30
|
+
for (const line of lines) {
|
|
31
|
+
this.lineCount += 1;
|
|
32
|
+
this.onLine(line);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
error(message) {
|
|
36
|
+
this.plain(`Error: ${message}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function isDebugEnabled(logger) {
|
|
40
|
+
return Boolean(Reflect.get(logger, 'debugEnabled'));
|
|
41
|
+
}
|
|
42
|
+
function createCapturedStepLogger(logger, onLine) {
|
|
43
|
+
return new CapturedStepLogger(isDebugEnabled(logger), onLine);
|
|
44
|
+
}
|
|
45
|
+
function compactLines(lines) {
|
|
46
|
+
const compacted = [];
|
|
47
|
+
let previousWasEmpty = false;
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
const isEmpty = line.trim().length === 0;
|
|
50
|
+
if (isEmpty && previousWasEmpty) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
compacted.push(line);
|
|
54
|
+
previousWasEmpty = isEmpty;
|
|
55
|
+
}
|
|
56
|
+
while (compacted[0]?.trim() === '') {
|
|
57
|
+
compacted.shift();
|
|
58
|
+
}
|
|
59
|
+
while (compacted[compacted.length - 1]?.trim() === '') {
|
|
60
|
+
compacted.pop();
|
|
61
|
+
}
|
|
62
|
+
return compacted;
|
|
63
|
+
}
|
|
64
|
+
function extractValue(lines, key) {
|
|
65
|
+
const prefix = `${key}: `;
|
|
66
|
+
const line = lines.find((entry) => entry.startsWith(prefix));
|
|
67
|
+
return line ? line.slice(prefix.length).trim() : undefined;
|
|
68
|
+
}
|
|
69
|
+
function extractLoginSummary(lines, copy) {
|
|
70
|
+
const summary = [];
|
|
71
|
+
const details = [];
|
|
72
|
+
const browserLine = lines.find((line) => line.includes('Automatic browser launch failed') ||
|
|
73
|
+
line.includes('Browser opened'));
|
|
74
|
+
const callbackMode = extractValue(lines, 'Callback mode');
|
|
75
|
+
const continuationUrl = extractValue(lines, 'URL');
|
|
76
|
+
const account = extractValue(lines, 'Account');
|
|
77
|
+
const installation = extractValue(lines, 'Installation');
|
|
78
|
+
const accessTokenExpiresAt = extractValue(lines, 'Access token expires at');
|
|
79
|
+
if (browserLine) {
|
|
80
|
+
summary.push(copy.messages.summaryBrowser(browserLine));
|
|
81
|
+
}
|
|
82
|
+
if (callbackMode) {
|
|
83
|
+
summary.push(copy.messages.summaryCallbackMode(callbackMode));
|
|
84
|
+
}
|
|
85
|
+
if (continuationUrl) {
|
|
86
|
+
summary.push(copy.messages.summaryContinuationUrl(continuationUrl));
|
|
87
|
+
}
|
|
88
|
+
if (account) {
|
|
89
|
+
summary.push(copy.messages.summaryAccount(account));
|
|
90
|
+
}
|
|
91
|
+
if (installation) {
|
|
92
|
+
summary.push(copy.messages.summaryInstallation(installation));
|
|
93
|
+
}
|
|
94
|
+
if (accessTokenExpiresAt) {
|
|
95
|
+
summary.push(copy.messages.summaryAccessTokenExpiresAt(accessTokenExpiresAt));
|
|
96
|
+
}
|
|
97
|
+
for (const line of lines) {
|
|
98
|
+
if (line.startsWith('Login context') ||
|
|
99
|
+
line.startsWith('Login complete') ||
|
|
100
|
+
/^-+$/.test(line.trim())) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (line.includes('Automatic browser launch failed') || line.startsWith('URL:')) {
|
|
104
|
+
details.push(line);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (line.includes('Do not enter credentials inside the terminal.')) {
|
|
108
|
+
details.push(line);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
summary,
|
|
114
|
+
details: compactLines(details),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function extractDoctorSummary(lines, copy) {
|
|
118
|
+
const summary = [];
|
|
119
|
+
const environment = extractValue(lines, 'Environment');
|
|
120
|
+
const apiBaseUrl = extractValue(lines, 'API base URL');
|
|
121
|
+
const root = extractValue(lines, 'Root');
|
|
122
|
+
const authState = lines.find((line) => line.startsWith('- Auth token state file'));
|
|
123
|
+
const installationState = lines.find((line) => line.startsWith('- Installation state file'));
|
|
124
|
+
if (environment) {
|
|
125
|
+
summary.push(copy.messages.summaryEnvironment(environment));
|
|
126
|
+
}
|
|
127
|
+
if (apiBaseUrl) {
|
|
128
|
+
summary.push(copy.messages.summaryApiBaseUrl(apiBaseUrl));
|
|
129
|
+
}
|
|
130
|
+
if (root) {
|
|
131
|
+
summary.push(copy.messages.summaryRoot(root));
|
|
132
|
+
}
|
|
133
|
+
if (authState) {
|
|
134
|
+
summary.push(copy.messages.summaryAuthState(authState.replace(/^- /, '')));
|
|
135
|
+
}
|
|
136
|
+
if (installationState) {
|
|
137
|
+
summary.push(copy.messages.summaryInstallationState(installationState.replace(/^- /, '')));
|
|
138
|
+
}
|
|
139
|
+
return { summary };
|
|
140
|
+
}
|
|
141
|
+
function extractUsageSummary(lines, copy) {
|
|
142
|
+
const summary = [];
|
|
143
|
+
let section = '';
|
|
144
|
+
for (const line of lines) {
|
|
145
|
+
if (!line.trim() || /^-+$/.test(line.trim())) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (line === 'Plan' ||
|
|
149
|
+
line === 'Daily report' ||
|
|
150
|
+
line === 'Intelligence quota') {
|
|
151
|
+
section = line;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (section === 'Plan') {
|
|
155
|
+
const currentPlan = extractValue([line], 'Current plan');
|
|
156
|
+
const commercialStatus = extractValue([line], 'Commercial status');
|
|
157
|
+
if (currentPlan) {
|
|
158
|
+
summary.push(copy.messages.summaryPlan(currentPlan));
|
|
159
|
+
}
|
|
160
|
+
if (commercialStatus) {
|
|
161
|
+
summary.push(copy.messages.summaryCommercialStatus(commercialStatus));
|
|
162
|
+
}
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (section === 'Daily report') {
|
|
166
|
+
const status = extractValue([line], 'Status');
|
|
167
|
+
const lockedReport = extractValue([line], 'Locked report');
|
|
168
|
+
if (status) {
|
|
169
|
+
summary.push(copy.messages.summaryDailyReport(status));
|
|
170
|
+
}
|
|
171
|
+
if (lockedReport) {
|
|
172
|
+
summary.push(copy.messages.summaryLockedReport(lockedReport));
|
|
173
|
+
}
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (section === 'Intelligence quota') {
|
|
177
|
+
const status = extractValue([line], 'Status');
|
|
178
|
+
if (status) {
|
|
179
|
+
summary.push(copy.messages.summaryIntelligence(status));
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const normalized = line.replace(/^- /, '');
|
|
183
|
+
const resetCadence = extractValue([normalized], 'Reset cadence');
|
|
184
|
+
if (resetCadence) {
|
|
185
|
+
summary.push(copy.messages.summaryResetCadence(resetCadence));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return { summary };
|
|
190
|
+
}
|
|
191
|
+
function createSpinner(text, isInteractive) {
|
|
192
|
+
if (!isInteractive || !process.stdout.isTTY) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
return (0, ora_1.default)({
|
|
196
|
+
text,
|
|
197
|
+
color: 'cyan',
|
|
198
|
+
discardStdin: false,
|
|
199
|
+
isEnabled: true,
|
|
200
|
+
stream: process.stdout,
|
|
201
|
+
}).start();
|
|
202
|
+
}
|
|
203
|
+
function resolveDetailsTitle(copy, boxTitle) {
|
|
204
|
+
if (boxTitle === copy.boxes.loginOutput) {
|
|
205
|
+
return copy.boxes.loginDetails;
|
|
206
|
+
}
|
|
207
|
+
if (boxTitle === copy.boxes.doctorOutput) {
|
|
208
|
+
return copy.boxes.doctorDetails;
|
|
209
|
+
}
|
|
210
|
+
return copy.boxes.usageDetails;
|
|
211
|
+
}
|
|
212
|
+
function parseAgentIds(raw, copy) {
|
|
213
|
+
if (!raw) {
|
|
214
|
+
return [];
|
|
215
|
+
}
|
|
216
|
+
const supported = new Set((0, target_registry_1.getAgentTargetRegistry)().map((target) => target.id));
|
|
217
|
+
return raw
|
|
218
|
+
.split(',')
|
|
219
|
+
.map((value) => value.trim().toLowerCase())
|
|
220
|
+
.filter(Boolean)
|
|
221
|
+
.map((value) => {
|
|
222
|
+
if (!supported.has(value)) {
|
|
223
|
+
throw new Error(copy.errors.unsupportedAgent(value, Array.from(supported)));
|
|
224
|
+
}
|
|
225
|
+
return value;
|
|
226
|
+
})
|
|
227
|
+
.filter((value, index, items) => items.indexOf(value) === index);
|
|
228
|
+
}
|
|
229
|
+
function parseScope(raw, copy) {
|
|
230
|
+
if (!raw) {
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
if (raw === 'project' || raw === 'user') {
|
|
234
|
+
return raw;
|
|
235
|
+
}
|
|
236
|
+
throw new Error(copy.errors.invalidScopeOption);
|
|
237
|
+
}
|
|
238
|
+
function parsePositionalScope(positionals, copy) {
|
|
239
|
+
if (positionals.length === 0) {
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
if (positionals.length !== 1 || positionals[0] !== '.') {
|
|
243
|
+
throw new Error(copy.errors.invalidPositionalArgument);
|
|
244
|
+
}
|
|
245
|
+
return 'project';
|
|
246
|
+
}
|
|
247
|
+
function getScopeSurface(scope) {
|
|
248
|
+
return scope === 'project' ? 'workspace' : 'user';
|
|
249
|
+
}
|
|
250
|
+
function defaultAgentsForScope(detectedTargets, scope) {
|
|
251
|
+
const detected = detectedTargets
|
|
252
|
+
.filter((target) => target.detectedIn.includes(getScopeSurface(scope)))
|
|
253
|
+
.map((target) => target.targetId);
|
|
254
|
+
return detected;
|
|
255
|
+
}
|
|
256
|
+
function buildAgentChoices(detectedTargets, scope, defaults, copy) {
|
|
257
|
+
return detectedTargets
|
|
258
|
+
.filter((target) => !(scope === 'project' && target.targetId === 'openclaw'))
|
|
259
|
+
.map((target) => ({
|
|
260
|
+
value: target.targetId,
|
|
261
|
+
label: target.displayName,
|
|
262
|
+
description: copy.messages.agentChoiceDescription(target, scope),
|
|
263
|
+
checked: defaults.includes(target.targetId),
|
|
264
|
+
}));
|
|
265
|
+
}
|
|
266
|
+
async function resolveInitLocale(input) {
|
|
267
|
+
const parsedArgs = (0, argv_1.parseCommandArgs)(input.args);
|
|
268
|
+
const yes = (0, argv_1.getBooleanOption)(parsedArgs, 'yes');
|
|
269
|
+
const explicitLocale = (0, locale_1.parseSupportedLocale)((0, argv_1.getStringOption)(parsedArgs, 'lang'), '--lang');
|
|
270
|
+
if (explicitLocale) {
|
|
271
|
+
return {
|
|
272
|
+
parsedArgs,
|
|
273
|
+
locale: explicitLocale,
|
|
274
|
+
shouldPersistLocale: !input.hasConfiguredLocale || explicitLocale !== input.preferredLocale,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
if (input.hasConfiguredLocale) {
|
|
278
|
+
return {
|
|
279
|
+
parsedArgs,
|
|
280
|
+
locale: input.preferredLocale,
|
|
281
|
+
shouldPersistLocale: false,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
if (!input.isInteractive || yes || !input.prompt) {
|
|
285
|
+
return {
|
|
286
|
+
parsedArgs,
|
|
287
|
+
locale: locale_1.DEFAULT_LOCALE,
|
|
288
|
+
shouldPersistLocale: false,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
const locale = await input.prompt.select({
|
|
292
|
+
message: 'Select CLI language / 选择 CLI 语言',
|
|
293
|
+
choices: [
|
|
294
|
+
{
|
|
295
|
+
value: 'en',
|
|
296
|
+
label: 'English',
|
|
297
|
+
description: 'Use English for the init flow',
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
value: 'zh-CN',
|
|
301
|
+
label: '简体中文',
|
|
302
|
+
description: '在 init 流程中使用中文',
|
|
303
|
+
},
|
|
304
|
+
],
|
|
305
|
+
defaultValue: locale_1.DEFAULT_LOCALE,
|
|
306
|
+
});
|
|
307
|
+
return {
|
|
308
|
+
parsedArgs,
|
|
309
|
+
locale,
|
|
310
|
+
shouldPersistLocale: true,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
function resolveInitOptions(input) {
|
|
314
|
+
const resolve = async () => {
|
|
315
|
+
const { parsedArgs, locale, shouldPersistLocale } = await resolveInitLocale({
|
|
316
|
+
args: input.args,
|
|
317
|
+
preferredLocale: input.preferredLocale,
|
|
318
|
+
hasConfiguredLocale: input.hasConfiguredLocale,
|
|
319
|
+
isInteractive: input.isInteractive,
|
|
320
|
+
prompt: input.prompt,
|
|
321
|
+
});
|
|
322
|
+
const copy = (0, init_copy_1.getInitCopy)(locale);
|
|
323
|
+
const parsedAgents = parseAgentIds((0, argv_1.getStringOption)(parsedArgs, 'agents'), copy);
|
|
324
|
+
const parsedScope = parseScope((0, argv_1.getStringOption)(parsedArgs, 'scope'), copy);
|
|
325
|
+
const positionalScope = parsePositionalScope(parsedArgs.positionals, copy);
|
|
326
|
+
const skipLogin = (0, argv_1.getBooleanOption)(parsedArgs, 'skip-login');
|
|
327
|
+
const force = (0, argv_1.getBooleanOption)(parsedArgs, 'force');
|
|
328
|
+
const yes = (0, argv_1.getBooleanOption)(parsedArgs, 'yes');
|
|
329
|
+
let agents = parsedAgents;
|
|
330
|
+
let scope = positionalScope ?? parsedScope;
|
|
331
|
+
if (positionalscopeAndScopeConflict(positionalScope, parsedScope)) {
|
|
332
|
+
throw new Error(copy.errors.initDotScopeConflict);
|
|
333
|
+
}
|
|
334
|
+
if (!scope) {
|
|
335
|
+
if (!input.isInteractive) {
|
|
336
|
+
throw new Error(copy.errors.nonInteractiveNeedsScope);
|
|
337
|
+
}
|
|
338
|
+
if (yes) {
|
|
339
|
+
scope = 'project';
|
|
340
|
+
}
|
|
341
|
+
else if (input.prompt) {
|
|
342
|
+
scope = await input.prompt.select({
|
|
343
|
+
message: copy.prompts.selectInstallLocation,
|
|
344
|
+
choices: [
|
|
345
|
+
{
|
|
346
|
+
value: 'project',
|
|
347
|
+
label: copy.choices.currentProject,
|
|
348
|
+
description: copy.choices.currentProjectDescription,
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
value: 'user',
|
|
352
|
+
label: copy.choices.global,
|
|
353
|
+
description: copy.choices.globalDescription,
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
defaultValue: 'project',
|
|
357
|
+
locale,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (!scope) {
|
|
362
|
+
throw new Error(copy.errors.unresolvedScope);
|
|
363
|
+
}
|
|
364
|
+
if (!agents.length) {
|
|
365
|
+
if (!input.isInteractive) {
|
|
366
|
+
throw new Error(copy.errors.nonInteractiveNeedsAgents);
|
|
367
|
+
}
|
|
368
|
+
const defaults = defaultAgentsForScope(input.detectedTargets, scope);
|
|
369
|
+
if (yes) {
|
|
370
|
+
agents =
|
|
371
|
+
defaults.length > 0
|
|
372
|
+
? defaults
|
|
373
|
+
: (0, target_registry_1.getAgentTargetRegistry)().map((target) => target.id);
|
|
374
|
+
}
|
|
375
|
+
else if (input.prompt) {
|
|
376
|
+
agents = await input.prompt.multiselect({
|
|
377
|
+
message: copy.prompts.selectAgentApps,
|
|
378
|
+
choices: buildAgentChoices(input.detectedTargets, scope, defaults, copy),
|
|
379
|
+
locale,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (!agents.length) {
|
|
384
|
+
throw new Error(copy.errors.noAgentSelected);
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
agents,
|
|
388
|
+
scope,
|
|
389
|
+
skipLogin,
|
|
390
|
+
force,
|
|
391
|
+
yes,
|
|
392
|
+
interactive: input.isInteractive,
|
|
393
|
+
locale,
|
|
394
|
+
shouldPersistLocale,
|
|
395
|
+
};
|
|
396
|
+
};
|
|
397
|
+
return resolve();
|
|
398
|
+
}
|
|
399
|
+
function positionalscopeAndScopeConflict(positionalScope, parsedScope) {
|
|
400
|
+
return Boolean(positionalScope &&
|
|
401
|
+
parsedScope &&
|
|
402
|
+
positionalScope !== parsedScope);
|
|
403
|
+
}
|
|
404
|
+
function describeDetection(presenter, copy, detectedTargets) {
|
|
405
|
+
presenter.section(copy.sections.detection);
|
|
406
|
+
for (const target of detectedTargets) {
|
|
407
|
+
const summary = target.detected ? copy.labels.detected : copy.labels.notDetected;
|
|
408
|
+
presenter.list([
|
|
409
|
+
`${target.displayName}: ${summary}`,
|
|
410
|
+
...(target.detectedIn.length > 0
|
|
411
|
+
? target.detectedIn.map((surface) => copy.messages.detectedIn(target.displayName, surface, target.targetId))
|
|
412
|
+
: [copy.messages.notDetectedReason(target.displayName)]),
|
|
413
|
+
]);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
function describePlan(presenter, copy, options, prepared, cwd) {
|
|
417
|
+
presenter.section(copy.sections.installationPlan);
|
|
418
|
+
presenter.list([
|
|
419
|
+
`${copy.labels.installLocation}: ${(0, init_copy_1.formatInstallLocationLabel)(options.locale, options.scope)}`,
|
|
420
|
+
`${copy.labels.targets}: ${prepared
|
|
421
|
+
.map((entry) => entry.target.displayName)
|
|
422
|
+
.join(', ')}`,
|
|
423
|
+
]);
|
|
424
|
+
for (const entry of prepared) {
|
|
425
|
+
const relativeRoot = (0, node_path_1.relative)(cwd, entry.rootDir) || '.';
|
|
426
|
+
presenter.list([
|
|
427
|
+
`${entry.target.displayName} ${copy.labels.root}: ${relativeRoot}`,
|
|
428
|
+
`${entry.target.displayName} ${copy.labels.create}: ${entry.analysis.toCreate.length}`,
|
|
429
|
+
`${entry.target.displayName} ${copy.labels.refresh}: ${entry.analysis.toRefresh.length}`,
|
|
430
|
+
`${entry.target.displayName} ${copy.labels.conflicts}: ${entry.analysis.conflicts.length}`,
|
|
431
|
+
]);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
async function confirmConflicts(prompt, prepared, copy) {
|
|
435
|
+
if (!prompt) {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
const files = prepared.flatMap((entry) => entry.analysis.conflicts.map((relativePath) => `${entry.target.displayName}: ${relativePath}`));
|
|
439
|
+
return prompt.confirm(`${copy.prompts.confirmOverwriteConflicts}\n${files
|
|
440
|
+
.map((file) => `- ${file}`)
|
|
441
|
+
.join('\n')}`, false);
|
|
442
|
+
}
|
|
443
|
+
function describeApplied(presenter, copy, applied, cwd) {
|
|
444
|
+
presenter.section(copy.sections.installation);
|
|
445
|
+
for (const entry of applied) {
|
|
446
|
+
const relativeRoot = (0, node_path_1.relative)(cwd, entry.rootDir) || '.';
|
|
447
|
+
presenter.list([
|
|
448
|
+
`${entry.target.displayName}: ${copy.labels.installedAt} ${relativeRoot}`,
|
|
449
|
+
`${entry.target.displayName}: ${copy.labels.created} ${entry.created.length}`,
|
|
450
|
+
`${entry.target.displayName}: ${copy.labels.refreshed} ${entry.refreshed.length}`,
|
|
451
|
+
`${entry.target.displayName}: ${copy.labels.overwritten} ${entry.overwritten.length}`,
|
|
452
|
+
]);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
async function runVerification(context, presenter, copy, options, dependencies) {
|
|
456
|
+
presenter.section(copy.sections.verification);
|
|
457
|
+
await runCommandInBox({
|
|
458
|
+
context,
|
|
459
|
+
presenter,
|
|
460
|
+
copy,
|
|
461
|
+
isInteractive: dependencies.isInteractive,
|
|
462
|
+
spinnerText: copy.messages.spinnerDoctor,
|
|
463
|
+
statusLabels: copy.statuses,
|
|
464
|
+
stepLabel: copy.steps.doctor,
|
|
465
|
+
boxTitle: copy.boxes.doctorOutput,
|
|
466
|
+
command: dependencies.verifyDoctor,
|
|
467
|
+
nonZeroError: copy.errors.postInitDoctorFailed,
|
|
468
|
+
summarize: extractDoctorSummary,
|
|
469
|
+
});
|
|
470
|
+
if (options.skipLogin) {
|
|
471
|
+
presenter.step('skipped', copy.statuses.skipped, copy.steps.usageSkipped);
|
|
472
|
+
presenter.list([
|
|
473
|
+
copy.messages.usageVerificationSkippedDeferred,
|
|
474
|
+
]);
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
await runCommandInBox({
|
|
478
|
+
context,
|
|
479
|
+
presenter,
|
|
480
|
+
copy,
|
|
481
|
+
isInteractive: dependencies.isInteractive,
|
|
482
|
+
spinnerText: copy.messages.spinnerUsage,
|
|
483
|
+
statusLabels: copy.statuses,
|
|
484
|
+
stepLabel: copy.steps.usage,
|
|
485
|
+
boxTitle: copy.boxes.usageOutput,
|
|
486
|
+
command: dependencies.verifyUsage,
|
|
487
|
+
nonZeroError: copy.errors.postInitUsageFailed,
|
|
488
|
+
summarize: extractUsageSummary,
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
function printRestartGuidance(presenter, copy, applied) {
|
|
492
|
+
presenter.section(copy.sections.nextSteps);
|
|
493
|
+
presenter.step('completed', copy.statuses.completed, copy.steps.completed);
|
|
494
|
+
presenter.list([
|
|
495
|
+
`${copy.labels.configuredTargets}: ${applied
|
|
496
|
+
.map((entry) => entry.target.displayName)
|
|
497
|
+
.join(', ')}`,
|
|
498
|
+
copy.messages.restartAgent,
|
|
499
|
+
copy.messages.startUsingAfterRestart,
|
|
500
|
+
]);
|
|
501
|
+
}
|
|
502
|
+
async function runCommandInBox(input) {
|
|
503
|
+
input.presenter.step('in_progress', input.statusLabels.inProgress, input.stepLabel);
|
|
504
|
+
const capturedLines = [];
|
|
505
|
+
const logger = createCapturedStepLogger(input.context.logger, (line) => {
|
|
506
|
+
capturedLines.push(line);
|
|
507
|
+
});
|
|
508
|
+
const spinner = createSpinner(input.spinnerText, input.isInteractive);
|
|
509
|
+
try {
|
|
510
|
+
const exitCode = await input.command(logger);
|
|
511
|
+
if (exitCode !== 0) {
|
|
512
|
+
throw new Error(input.nonZeroError);
|
|
513
|
+
}
|
|
514
|
+
spinner?.stop();
|
|
515
|
+
const rendered = input.summarize(capturedLines, input.copy);
|
|
516
|
+
const box = input.presenter.openBox(input.boxTitle);
|
|
517
|
+
for (const line of rendered.summary) {
|
|
518
|
+
box.write(line);
|
|
519
|
+
}
|
|
520
|
+
box.close();
|
|
521
|
+
if (rendered.details && rendered.details.length > 0) {
|
|
522
|
+
const detailsBox = input.presenter.openBox(resolveDetailsTitle(input.copy, input.boxTitle));
|
|
523
|
+
for (const line of rendered.details) {
|
|
524
|
+
detailsBox.write(line);
|
|
525
|
+
}
|
|
526
|
+
detailsBox.close();
|
|
527
|
+
}
|
|
528
|
+
input.presenter.step('completed', input.statusLabels.completed, input.stepLabel);
|
|
529
|
+
}
|
|
530
|
+
catch (error) {
|
|
531
|
+
spinner?.stop();
|
|
532
|
+
const box = input.presenter.openBox(resolveDetailsTitle(input.copy, input.boxTitle));
|
|
533
|
+
const detailLines = compactLines(capturedLines);
|
|
534
|
+
if (detailLines.length > 0) {
|
|
535
|
+
for (const line of detailLines) {
|
|
536
|
+
box.write(line);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
const message = error instanceof Error ? error.message : 'Unknown subcommand failure.';
|
|
541
|
+
box.write(`Error: ${message}`);
|
|
542
|
+
}
|
|
543
|
+
box.close();
|
|
544
|
+
input.presenter.step('failed', input.statusLabels.failed, input.stepLabel);
|
|
545
|
+
throw error;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
async function runInitFlow(context, args, partialDependencies = {}) {
|
|
549
|
+
const dependencies = {
|
|
550
|
+
cwd: process.cwd(),
|
|
551
|
+
homeDir: (0, node_os_1.homedir)(),
|
|
552
|
+
isInteractive: Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY),
|
|
553
|
+
promptFactory: prompt_1.createTerminalPrompt,
|
|
554
|
+
showWelcome: presentation_1.showVisionAlphaWelcome,
|
|
555
|
+
pauseForExit: presentation_1.waitForTerminalEnter,
|
|
556
|
+
exitProcess: (code) => process.exit(code),
|
|
557
|
+
...partialDependencies,
|
|
558
|
+
};
|
|
559
|
+
const parsedArgs = (0, argv_1.parseCommandArgs)(args);
|
|
560
|
+
const skipInteractiveWelcome = (0, argv_1.getBooleanOption)(parsedArgs, 'yes');
|
|
561
|
+
const detectedTargets = await (0, detect_targets_1.detectAgentTargets)({
|
|
562
|
+
cwd: dependencies.cwd,
|
|
563
|
+
homeDir: dependencies.homeDir,
|
|
564
|
+
});
|
|
565
|
+
const prompt = dependencies.isInteractive ? dependencies.promptFactory() : null;
|
|
566
|
+
let shouldForceExit = false;
|
|
567
|
+
let exitCode = 1;
|
|
568
|
+
try {
|
|
569
|
+
if (dependencies.isInteractive && !skipInteractiveWelcome) {
|
|
570
|
+
await dependencies.showWelcome();
|
|
571
|
+
}
|
|
572
|
+
const options = await resolveInitOptions({
|
|
573
|
+
args,
|
|
574
|
+
detectedTargets,
|
|
575
|
+
isInteractive: dependencies.isInteractive,
|
|
576
|
+
prompt,
|
|
577
|
+
preferredLocale: context.runtimeConfig.locale,
|
|
578
|
+
hasConfiguredLocale: context.runtimeConfig.localeConfigured,
|
|
579
|
+
});
|
|
580
|
+
const copy = (0, init_copy_1.getInitCopy)(options.locale);
|
|
581
|
+
const presenter = (0, presentation_1.createInitPresenter)(context.logger);
|
|
582
|
+
if (options.shouldPersistLocale) {
|
|
583
|
+
await (0, runtime_config_1.saveRuntimeConfig)(context.paths, {
|
|
584
|
+
locale: options.locale,
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
context.runtimeConfig.locale = options.locale;
|
|
588
|
+
context.runtimeConfig.localeConfigured = true;
|
|
589
|
+
describeDetection(presenter, copy, detectedTargets);
|
|
590
|
+
const prepared = await (0, installer_1.prepareInstallations)({
|
|
591
|
+
agentIds: options.agents,
|
|
592
|
+
scope: options.scope,
|
|
593
|
+
cwd: dependencies.cwd,
|
|
594
|
+
homeDir: dependencies.homeDir,
|
|
595
|
+
});
|
|
596
|
+
describePlan(presenter, copy, options, prepared, dependencies.cwd);
|
|
597
|
+
const hasConflicts = prepared.some((entry) => entry.analysis.conflicts.length > 0);
|
|
598
|
+
let allowUnmanagedOverwrite = options.force;
|
|
599
|
+
if (hasConflicts && !allowUnmanagedOverwrite) {
|
|
600
|
+
if (!options.interactive) {
|
|
601
|
+
throw new Error(copy.errors.unmanagedFilesNeedOverride);
|
|
602
|
+
}
|
|
603
|
+
allowUnmanagedOverwrite = await confirmConflicts(prompt, prepared, copy);
|
|
604
|
+
if (!allowUnmanagedOverwrite) {
|
|
605
|
+
throw new Error(copy.errors.cancelledForUnmanagedFiles);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
const installSpinner = createSpinner(copy.messages.spinnerInstalling, dependencies.isInteractive);
|
|
609
|
+
let applied;
|
|
610
|
+
try {
|
|
611
|
+
applied = await (0, installer_1.applyInstallations)(prepared, {
|
|
612
|
+
allowUnmanagedOverwrite,
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
finally {
|
|
616
|
+
installSpinner?.stop();
|
|
617
|
+
}
|
|
618
|
+
describeApplied(presenter, copy, applied, dependencies.cwd);
|
|
619
|
+
if (options.skipLogin) {
|
|
620
|
+
presenter.section(copy.sections.login);
|
|
621
|
+
presenter.step('skipped', copy.statuses.skipped, copy.steps.loginSkipped);
|
|
622
|
+
const box = presenter.openBox(copy.boxes.loginOutput);
|
|
623
|
+
box.write(copy.messages.loginSkippedByFlag);
|
|
624
|
+
box.write(copy.messages.runLoginLater);
|
|
625
|
+
box.close();
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
presenter.section(copy.sections.login);
|
|
629
|
+
await runCommandInBox({
|
|
630
|
+
context,
|
|
631
|
+
presenter,
|
|
632
|
+
copy,
|
|
633
|
+
isInteractive: dependencies.isInteractive,
|
|
634
|
+
spinnerText: copy.messages.spinnerLoggingIn,
|
|
635
|
+
statusLabels: copy.statuses,
|
|
636
|
+
stepLabel: copy.steps.login,
|
|
637
|
+
boxTitle: copy.boxes.loginOutput,
|
|
638
|
+
command: dependencies.login,
|
|
639
|
+
nonZeroError: 'Login phase failed after installation.',
|
|
640
|
+
summarize: extractLoginSummary,
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
await runVerification(context, presenter, copy, options, dependencies);
|
|
644
|
+
printRestartGuidance(presenter, copy, applied);
|
|
645
|
+
if (options.interactive) {
|
|
646
|
+
presenter.list([copy.messages.pressEnterToExit]);
|
|
647
|
+
presenter.emptyLine();
|
|
648
|
+
await dependencies.pauseForExit();
|
|
649
|
+
shouldForceExit = true;
|
|
650
|
+
}
|
|
651
|
+
presenter.emptyLine();
|
|
652
|
+
exitCode = 0;
|
|
653
|
+
return exitCode;
|
|
654
|
+
}
|
|
655
|
+
finally {
|
|
656
|
+
await prompt?.close();
|
|
657
|
+
if (shouldForceExit && exitCode === 0) {
|
|
658
|
+
dependencies.exitProcess(0);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|