@aopslabs/aops 0.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/LICENSE +19 -0
- package/NOTICE +7 -0
- package/README.md +203 -0
- package/assets/agent-assets/core/SKILL.md +49 -0
- package/assets/agent-assets/core/references/agentspace/SKILL.md +78 -0
- package/assets/agent-assets/core/references/aops-cli-core/SKILL.md +108 -0
- package/assets/agent-assets/core/references/chatv3/SKILL.md +48 -0
- package/assets/agent-assets/core/references/collaborative-work/SKILL.md +85 -0
- package/assets/agent-assets/core/references/discuss/SKILL.md +66 -0
- package/assets/agent-assets/core/references/docman/SKILL.md +69 -0
- package/assets/agent-assets/core/references/hosted-chat/SKILL.md +64 -0
- package/assets/agent-assets/core/references/mission/SKILL.md +54 -0
- package/assets/agent-assets/core/references/projectman/SKILL.md +86 -0
- package/assets/agent-assets/core/references/sys/SKILL.md +36 -0
- package/assets/agent-assets/core/references/view/SKILL.md +58 -0
- package/assets/agent-assets/core/references/working-disciplines/SKILL.md +69 -0
- package/assets/agent-assets/core/user-guides/agent-assets.md +81 -0
- package/assets/agent-assets/core/user-guides/agentspace.md +1098 -0
- package/assets/agent-assets/core/user-guides/aops-cli.md +1107 -0
- package/assets/agent-assets/core/user-guides/aops-system.md +63 -0
- package/assets/agent-assets/core/user-guides/chatv3.md +113 -0
- package/assets/agent-assets/core/user-guides/docman.md +162 -0
- package/assets/agent-assets/core/user-guides/projectman.md +212 -0
- package/assets/agent-assets/core/user-guides/sys.md +94 -0
- package/assets/agent-assets/core/user-guides/working-disciplines.md +588 -0
- package/assets/agent-assets/gateway/aops/SKILL.md +14 -0
- package/assets/r6-remote-session-baseline.json +19 -0
- package/assets/skills/aops-install/SKILL.md +231 -0
- package/assets/skills/aops-install/agents/openai.yaml +4 -0
- package/dist/commands/activity.js +352 -0
- package/dist/commands/agent-profile.js +653 -0
- package/dist/commands/agent.js +710 -0
- package/dist/commands/agents-md.js +125 -0
- package/dist/commands/api.js +84 -0
- package/dist/commands/archive.js +873 -0
- package/dist/commands/artifact.js +535 -0
- package/dist/commands/assets.js +1414 -0
- package/dist/commands/auth/device-login.js +1 -0
- package/dist/commands/auth/legacy-export.js +177 -0
- package/dist/commands/auth/login.js +426 -0
- package/dist/commands/chat.js +1363 -0
- package/dist/commands/chatv3.js +1684 -0
- package/dist/commands/checkpoint.js +549 -0
- package/dist/commands/commercial-artifact.js +475 -0
- package/dist/commands/commercial-license.js +594 -0
- package/dist/commands/community-auth.js +62 -0
- package/dist/commands/community-cockpit.js +185 -0
- package/dist/commands/community-console.js +109 -0
- package/dist/commands/community-doctor.js +335 -0
- package/dist/commands/community-server.js +2062 -0
- package/dist/commands/community-setup.js +284 -0
- package/dist/commands/discuss.js +1448 -0
- package/dist/commands/doc.js +5219 -0
- package/dist/commands/experience.js +922 -0
- package/dist/commands/host.js +1127 -0
- package/dist/commands/init.js +118 -0
- package/dist/commands/memory.js +3129 -0
- package/dist/commands/mission.js +562 -0
- package/dist/commands/official-catalog.js +134 -0
- package/dist/commands/plan.js +84 -0
- package/dist/commands/playbook.js +415 -0
- package/dist/commands/pm/context.js +6 -0
- package/dist/commands/pm/index.js +701 -0
- package/dist/commands/pm/projectman.js +6266 -0
- package/dist/commands/project.js +1080 -0
- package/dist/commands/prompt.js +1024 -0
- package/dist/commands/repo-sync.js +1907 -0
- package/dist/commands/resource.js +527 -0
- package/dist/commands/skill.js +1211 -0
- package/dist/commands/start-disciplines.js +510 -0
- package/dist/commands/start.js +1343 -0
- package/dist/commands/target.js +309 -0
- package/dist/commands/version.js +42 -0
- package/dist/commands/view.js +1852 -0
- package/dist/launchers/cockpit.js +28 -0
- package/dist/launchers/options.js +74 -0
- package/dist/launchers/server.js +41 -0
- package/dist/lib/agent-assets/envelope.js +83 -0
- package/dist/lib/agent-assets/gateway.js +15 -0
- package/dist/lib/agent-assets/guards.js +23 -0
- package/dist/lib/agent-assets/hosted-discovery.js +148 -0
- package/dist/lib/agent-assets/hosted-package-input.js +154 -0
- package/dist/lib/agent-assets/legacy-pointer-migration.js +677 -0
- package/dist/lib/agent-assets/native-fs.js +589 -0
- package/dist/lib/agent-assets/package-manifest.js +324 -0
- package/dist/lib/agent-assets/portable-path.js +67 -0
- package/dist/lib/agent-assets/release-input.js +177 -0
- package/dist/lib/agent-assets/roots.js +45 -0
- package/dist/lib/agent-assets/runtime-binding-reader.js +545 -0
- package/dist/lib/agent-assets/runtime-targets.js +50 -0
- package/dist/lib/agent-assets/store-reader.js +1212 -0
- package/dist/lib/agent-assets/store-types.js +1 -0
- package/dist/lib/agent-assets/store-writer.js +1484 -0
- package/dist/lib/agent-assets/types.js +1 -0
- package/dist/lib/agent-assets/unicode-case-folding-v15-1.generated.js +1548 -0
- package/dist/lib/commercial-final-readiness.js +504 -0
- package/dist/lib/commercial-lifecycle-smoke-isolation.js +236 -0
- package/dist/lib/commercial-managed-postgres-docker-adapter.js +274 -0
- package/dist/lib/commercial-setup-readiness-adapter.js +179 -0
- package/dist/lib/community-client-contract.js +164 -0
- package/dist/lib/community-cockpit-lifecycle.js +601 -0
- package/dist/lib/community-command-abort.js +59 -0
- package/dist/lib/community-diagnostic.js +237 -0
- package/dist/lib/community-docker-adapter.js +498 -0
- package/dist/lib/community-home.js +31 -0
- package/dist/lib/community-instance-contract.js +148 -0
- package/dist/lib/community-instance-layout.js +97 -0
- package/dist/lib/community-lifecycle.js +1631 -0
- package/dist/lib/community-migration-snapshot.js +770 -0
- package/dist/lib/community-native-application-recovery.js +425 -0
- package/dist/lib/community-native-child.js +240 -0
- package/dist/lib/community-native-database-recovery.js +456 -0
- package/dist/lib/community-native-lifecycle.js +2458 -0
- package/dist/lib/community-native-migration.js +339 -0
- package/dist/lib/community-native-postgres.js +596 -0
- package/dist/lib/community-operation-journal.js +773 -0
- package/dist/lib/community-operation-lock.js +596 -0
- package/dist/lib/community-release-resolver.js +291 -0
- package/dist/lib/community-release-verifier.js +475 -0
- package/dist/lib/community-repo-discovery.js +252 -0
- package/dist/lib/community-setup-server-env.js +203 -0
- package/dist/lib/external-url.js +110 -0
- package/dist/lib/official-catalog-gateway.js +108 -0
- package/dist/lib/official-catalog.js +364 -0
- package/dist/lib/server-bootstrap.js +240 -0
- package/dist/lib/setup-agent-assets-bridge.js +176 -0
- package/dist/lib/setup-agent-assets-release.js +52 -0
- package/dist/lib/setup-external-postgres.js +108 -0
- package/dist/lib/setup-init-orchestrator.js +990 -0
- package/dist/lib/setup-install-guide.js +52 -0
- package/dist/lib/setup-installer-release.js +47 -0
- package/dist/lib/setup-local-postgres.js +329 -0
- package/dist/lib/setup-official-catalog-bridge.js +148 -0
- package/dist/lib/setup-readiness.js +888 -0
- package/dist/lib/tui-launcher.js +59 -0
- package/dist/main.js +150 -0
- package/dist/seeds/agents-md.js +54 -0
- package/dist/utils/agent-gateway.js +275 -0
- package/dist/utils/agents-md.js +281 -0
- package/dist/utils/api.js +255 -0
- package/dist/utils/chatv3-session-store.js +185 -0
- package/dist/utils/command.js +67 -0
- package/dist/utils/community-host-runtime.js +376 -0
- package/dist/utils/config.js +1015 -0
- package/dist/utils/discussion-workspace.js +552 -0
- package/dist/utils/experience-workspace.js +326 -0
- package/dist/utils/guide-paths.js +67 -0
- package/dist/utils/hosted-sugar.js +56 -0
- package/dist/utils/hosted-workspace.js +229 -0
- package/dist/utils/memory-workspace.js +537 -0
- package/dist/utils/operator-runtime.js +199 -0
- package/dist/utils/password-crypto.js +39 -0
- package/dist/utils/playbook-workspace.js +479 -0
- package/dist/utils/project-context.js +255 -0
- package/dist/utils/prompts.js +70 -0
- package/dist/utils/refresh-race.js +28 -0
- package/dist/utils/repo-config.js +109 -0
- package/dist/utils/repo-first-projectman.js +194 -0
- package/dist/utils/repo-first-storage.js +13 -0
- package/dist/utils/repo-first-view.js +305 -0
- package/dist/utils/session-guidance.js +278 -0
- package/dist/utils/session-state.js +137 -0
- package/dist/utils/table.js +39 -0
- package/dist/utils/transient-fs.js +49 -0
- package/dist/utils/workspace-root.js +1 -0
- package/launchers/aops-cockpit.ps1 +15 -0
- package/launchers/aops-cockpit.sh +16 -0
- package/launchers/aops-server.ps1 +15 -0
- package/launchers/aops-server.sh +16 -0
- package/native/tui/win32-x64/aops-tui.exe +0 -0
- package/package.json +81 -0
|
@@ -0,0 +1,990 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { banner, logInfo, logSuccess, logWarn, withSpinner } from '@aopslabs/xf-cli-ui';
|
|
3
|
+
import { canonicalCommercialJson, managedInstallationLayoutBinding, sha256Commercial, } from '@aopslabs/artifact-trust-contracts';
|
|
4
|
+
import { runAuthLogin } from '../commands/auth/login.js';
|
|
5
|
+
import { runCommunityServerSetup } from '../commands/community-server.js';
|
|
6
|
+
import { runTargetAdd } from '../commands/target.js';
|
|
7
|
+
import { promptConfirm, promptInput, promptPassword, promptSelect } from '../utils/prompts.js';
|
|
8
|
+
import { inspectSetupReadiness, parseSetupPath, SETUP_PATHS, } from './setup-readiness.js';
|
|
9
|
+
import { applySetupAgentAssets, SETUP_AGENT_ASSETS_GATEWAYS, } from './setup-agent-assets-bridge.js';
|
|
10
|
+
import { defaultLocalPostgresAdminUser, defaultLocalPostgresDatabase, provisionLocalPostgres, } from './setup-local-postgres.js';
|
|
11
|
+
import { isExternalPostgresTlsProbeError, probeExternalPostgresConnection, } from './setup-external-postgres.js';
|
|
12
|
+
import { assertCommunityNativeApplicationCurrent, inspectCommunityNativeInstall, inspectCommunityNativeSource, planCommunityNativeInstalledMigration, resolveCommunityNativeDefaultSourceRoot, stopCommunityNativeInstall, } from './community-native-lifecycle.js';
|
|
13
|
+
import { startCommunityNativeCockpit, stopCommunityNativeCockpit, } from './community-cockpit-lifecycle.js';
|
|
14
|
+
import { CommunityDiagnosticError, isCommunityDiagnosticV1, } from './community-diagnostic.js';
|
|
15
|
+
import { setupInstallerReleaseBinding, } from './setup-installer-release.js';
|
|
16
|
+
function canonicalSetupExposure(authProvider) {
|
|
17
|
+
void authProvider;
|
|
18
|
+
return 'loopback';
|
|
19
|
+
}
|
|
20
|
+
function assertInstalledApplicationCurrent(options) {
|
|
21
|
+
const inspection = inspectCommunityNativeInstall({
|
|
22
|
+
instanceName: options.instanceName,
|
|
23
|
+
dataRoot: options.dataRoot,
|
|
24
|
+
});
|
|
25
|
+
if (inspection.status !== 'installed' || !inspection.state) {
|
|
26
|
+
throw new Error(`community_native_install_not_current:${inspection.status}:${inspection.error ?? 'run_server_setup'}`);
|
|
27
|
+
}
|
|
28
|
+
const selected = inspectCommunityNativeSource(options.sourceRoot ?? resolveCommunityNativeDefaultSourceRoot());
|
|
29
|
+
if (path.resolve(selected.root) !== path.resolve(inspection.state.source.root) ||
|
|
30
|
+
selected.sourceFingerprint !== inspection.state.source.sourceFingerprint) {
|
|
31
|
+
throw new Error('community_native_selected_source_changed');
|
|
32
|
+
}
|
|
33
|
+
assertCommunityNativeApplicationCurrent(inspection.state);
|
|
34
|
+
}
|
|
35
|
+
export const SETUP_INSTALLER_PLAN_CONTRACT_VERSION = 'aops.setup-installer-plan/v2';
|
|
36
|
+
function normalizeNonEmpty(value) {
|
|
37
|
+
if (typeof value !== 'string')
|
|
38
|
+
return undefined;
|
|
39
|
+
const normalized = value.trim();
|
|
40
|
+
return normalized || undefined;
|
|
41
|
+
}
|
|
42
|
+
function createSetupInstallerPlan(options, selectedPath, security, readiness, effective, installerRelease, managedLayout) {
|
|
43
|
+
if ((installerRelease === undefined) !== (managedLayout === undefined)) {
|
|
44
|
+
throw new Error('setup_installer_release_layout_binding_incomplete');
|
|
45
|
+
}
|
|
46
|
+
const release = installerRelease
|
|
47
|
+
? setupInstallerReleaseBinding(installerRelease)
|
|
48
|
+
: null;
|
|
49
|
+
const layout = managedLayout
|
|
50
|
+
? managedInstallationLayoutBinding(managedLayout)
|
|
51
|
+
: null;
|
|
52
|
+
const material = {
|
|
53
|
+
schemaVersion: 1,
|
|
54
|
+
contractVersion: SETUP_INSTALLER_PLAN_CONTRACT_VERSION,
|
|
55
|
+
objectType: 'aops-setup-installer-plan-material-v1',
|
|
56
|
+
operation: 'install',
|
|
57
|
+
selection: {
|
|
58
|
+
path: selectedPath ?? null,
|
|
59
|
+
postgresConfig: effective.postgresConfig ? path.resolve(effective.postgresConfig) : null,
|
|
60
|
+
postgresTls: effective.postgresTls ?? null,
|
|
61
|
+
localPostgres: {
|
|
62
|
+
host: effective.localPostgresHost,
|
|
63
|
+
port: effective.localPostgresPort,
|
|
64
|
+
adminUser: effective.localPostgresAdminUser,
|
|
65
|
+
database: effective.localPostgresDatabase,
|
|
66
|
+
appUser: effective.localPostgresAppUser,
|
|
67
|
+
adminNoPassword: options.localPostgresAdminNoPassword === true,
|
|
68
|
+
},
|
|
69
|
+
apiBaseUrl: effective.apiBaseUrl ?? null,
|
|
70
|
+
instance: normalizeNonEmpty(options.instance) ?? null,
|
|
71
|
+
dataRoot: options.dataRoot ? path.resolve(options.dataRoot) : null,
|
|
72
|
+
sourceRoot: options.sourceRoot ? path.resolve(options.sourceRoot) : null,
|
|
73
|
+
port: options.port ?? null,
|
|
74
|
+
security: selectedPath && selectedPath !== 'cli-existing'
|
|
75
|
+
? {
|
|
76
|
+
authProvider: security.authProvider,
|
|
77
|
+
exposure: security.exposure,
|
|
78
|
+
}
|
|
79
|
+
: null,
|
|
80
|
+
targetName: effective.targetName ?? null,
|
|
81
|
+
targetAuthProvider: options.targetAuthProvider ?? null,
|
|
82
|
+
targetTlsPolicy: options.targetTlsPolicy ?? null,
|
|
83
|
+
agentAssets: normalizeAgentAssetsAction(options.agentAssets) ?? null,
|
|
84
|
+
agentAssetsRelease: options.agentAssetsRelease ? path.resolve(options.agentAssetsRelease) : null,
|
|
85
|
+
noCatalog: options.noCatalog === true,
|
|
86
|
+
catalogRelease: options.catalogRelease ? path.resolve(options.catalogRelease) : null,
|
|
87
|
+
catalogIdempotencyKey: normalizeNonEmpty(options.catalogIdempotencyKey) ?? null,
|
|
88
|
+
resume: options.resume === true,
|
|
89
|
+
},
|
|
90
|
+
readiness,
|
|
91
|
+
release,
|
|
92
|
+
layout,
|
|
93
|
+
};
|
|
94
|
+
const jsonMaterial = JSON.parse(JSON.stringify(material));
|
|
95
|
+
return Object.freeze({
|
|
96
|
+
schemaVersion: 1,
|
|
97
|
+
contractVersion: SETUP_INSTALLER_PLAN_CONTRACT_VERSION,
|
|
98
|
+
objectType: 'aops-setup-installer-plan-v1',
|
|
99
|
+
operation: 'install',
|
|
100
|
+
mutationFree: true,
|
|
101
|
+
planId: sha256Commercial(canonicalCommercialJson(jsonMaterial)),
|
|
102
|
+
path: selectedPath ?? null,
|
|
103
|
+
security: selectedPath && selectedPath !== 'cli-existing'
|
|
104
|
+
? Object.freeze({
|
|
105
|
+
authProvider: security.authProvider,
|
|
106
|
+
exposure: security.exposure,
|
|
107
|
+
})
|
|
108
|
+
: null,
|
|
109
|
+
release,
|
|
110
|
+
layout,
|
|
111
|
+
checks: Object.freeze(readiness.checks.map((check) => Object.freeze({
|
|
112
|
+
id: check.id,
|
|
113
|
+
state: check.state,
|
|
114
|
+
required: check.required,
|
|
115
|
+
}))),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function resolveSetupLocalSecurity(selectedPath, requestedAuth, requestedExposure) {
|
|
119
|
+
const rawAuth = normalizeNonEmpty(requestedAuth)?.toLowerCase();
|
|
120
|
+
const rawExposure = normalizeNonEmpty(requestedExposure)?.toLowerCase();
|
|
121
|
+
if (rawAuth && rawAuth !== 'trusted-local') {
|
|
122
|
+
if (rawAuth === 'authv2-jwt-session' || rawAuth === 'remote-session') {
|
|
123
|
+
throw new Error('setup_init_local_auth_retired:use_trusted-local_or_path_4_with_remote-session');
|
|
124
|
+
}
|
|
125
|
+
throw new Error('setup_init_auth_invalid:use_trusted-local');
|
|
126
|
+
}
|
|
127
|
+
if (rawExposure && rawExposure !== 'loopback') {
|
|
128
|
+
throw new Error('setup_init_exposure_invalid:use_loopback');
|
|
129
|
+
}
|
|
130
|
+
const explicit = Boolean(rawAuth || rawExposure);
|
|
131
|
+
if (explicit && (!selectedPath || selectedPath === 'cli-existing')) {
|
|
132
|
+
throw new Error('setup_init_local_security_only_valid_for_paths_1_2_or_3');
|
|
133
|
+
}
|
|
134
|
+
const authProvider = rawAuth ?? 'trusted-local';
|
|
135
|
+
const exposure = rawExposure ??
|
|
136
|
+
canonicalSetupExposure(authProvider);
|
|
137
|
+
const canonical = authProvider === 'trusted-local' && exposure === 'loopback';
|
|
138
|
+
if (!canonical) {
|
|
139
|
+
throw new Error('setup_init_security_mode_invalid:use-trusted-local-with-loopback');
|
|
140
|
+
}
|
|
141
|
+
if (selectedPath === 'native-container' &&
|
|
142
|
+
(authProvider !== 'trusted-local' || exposure !== 'loopback')) {
|
|
143
|
+
throw new Error('setup_init_path_2_requires_trusted-local_with_loopback');
|
|
144
|
+
}
|
|
145
|
+
return Object.freeze({ authProvider, exposure, explicit });
|
|
146
|
+
}
|
|
147
|
+
function validateManagedPostgresPassword(value) {
|
|
148
|
+
if (value.length < 16)
|
|
149
|
+
return 'Use at least 16 characters.';
|
|
150
|
+
if (value.length > 128)
|
|
151
|
+
return 'Use no more than 128 characters.';
|
|
152
|
+
if (value !== value.trim())
|
|
153
|
+
return 'Do not begin or end the password with whitespace.';
|
|
154
|
+
if (/\0|\r|\n/.test(value))
|
|
155
|
+
return 'The password cannot contain line breaks or NUL characters.';
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
function validateLocalPostgresIdentifier(value) {
|
|
159
|
+
return /^[a-z][a-z0-9_]{0,62}$/.test(value.trim().toLowerCase())
|
|
160
|
+
? true
|
|
161
|
+
: 'Use 1-63 lowercase letters, digits, or underscores; begin with a letter.';
|
|
162
|
+
}
|
|
163
|
+
function validateLocalPostgresAdminPassword(value) {
|
|
164
|
+
if (value.length > 1_024)
|
|
165
|
+
return 'Use no more than 1024 characters.';
|
|
166
|
+
if (/\0|\r|\n/.test(value))
|
|
167
|
+
return 'The password cannot contain line breaks or NUL characters.';
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
function printMigrationVerification(result) {
|
|
171
|
+
if (!result || typeof result !== 'object')
|
|
172
|
+
return;
|
|
173
|
+
const migration = result.migration;
|
|
174
|
+
if (!migration || typeof migration !== 'object')
|
|
175
|
+
return;
|
|
176
|
+
const summary = migration;
|
|
177
|
+
if (summary.status !== 'community-native-migration-verified')
|
|
178
|
+
return;
|
|
179
|
+
const action = summary.action === 'migrate' ? 'migrate' : 'verify-only';
|
|
180
|
+
const count = typeof summary.pendingMigrationCount === 'number' ? summary.pendingMigrationCount : 0;
|
|
181
|
+
const detail = action === 'migrate'
|
|
182
|
+
? `${count} migration${count === 1 ? '' : 's'} applied`
|
|
183
|
+
: 'schema already current';
|
|
184
|
+
logSuccess(`PostgreSQL schema verified (${detail}).`);
|
|
185
|
+
}
|
|
186
|
+
function printSetupReadiness(result) {
|
|
187
|
+
for (const check of result.checks) {
|
|
188
|
+
const prefix = check.state === 'ready'
|
|
189
|
+
? 'READY'
|
|
190
|
+
: check.state === 'not-applicable'
|
|
191
|
+
? 'N/A'
|
|
192
|
+
: check.state === 'unknown'
|
|
193
|
+
? 'WAIT'
|
|
194
|
+
: 'ACTION';
|
|
195
|
+
logInfo(`[${prefix}] ${check.summary}`);
|
|
196
|
+
if (isCommunityDiagnosticV1(check.data?.diagnostic)) {
|
|
197
|
+
logInfo(` Stage: ${check.data.diagnostic.phase}; Cause: ${check.data.diagnostic.cause.code}`);
|
|
198
|
+
}
|
|
199
|
+
if (check.next)
|
|
200
|
+
logInfo(` Next: ${check.next}`);
|
|
201
|
+
}
|
|
202
|
+
if (result.status === 'ready')
|
|
203
|
+
logSuccess('AOPS setup readiness checks passed.');
|
|
204
|
+
else
|
|
205
|
+
logWarn('AOPS setup has remaining actions.');
|
|
206
|
+
}
|
|
207
|
+
function normalizeAgentAssetsAction(value) {
|
|
208
|
+
const normalized = normalizeNonEmpty(value)?.toLowerCase();
|
|
209
|
+
if (!normalized)
|
|
210
|
+
return undefined;
|
|
211
|
+
if (normalized === 'status' || normalized === 'install' || normalized === 'repair' || normalized === 'skip') {
|
|
212
|
+
return normalized;
|
|
213
|
+
}
|
|
214
|
+
throw new Error('setup_init_agent_assets_action_invalid:choose_status_install_repair_or_skip');
|
|
215
|
+
}
|
|
216
|
+
function resolveAgentAssetsReleasePath(value) {
|
|
217
|
+
const normalized = normalizeNonEmpty(value);
|
|
218
|
+
if (!normalized)
|
|
219
|
+
throw new Error('setup_init_agent_assets_release_required_for_install');
|
|
220
|
+
if (/\0|\r|\n/.test(normalized) || /^[a-z][a-z0-9+.-]*:\/\//i.test(normalized)) {
|
|
221
|
+
throw new Error('setup_init_agent_assets_release_path_invalid');
|
|
222
|
+
}
|
|
223
|
+
return path.resolve(normalized);
|
|
224
|
+
}
|
|
225
|
+
function resolveOfficialCatalogReleasePath(value) {
|
|
226
|
+
const normalized = normalizeNonEmpty(value);
|
|
227
|
+
if (!normalized)
|
|
228
|
+
throw new Error('setup_init_catalog_release_required_or_use_--no-catalog');
|
|
229
|
+
if (/\0|\r|\n/.test(normalized) || /^[a-z][a-z0-9+.-]*:\/\//i.test(normalized)) {
|
|
230
|
+
throw new Error('setup_init_catalog_release_path_invalid');
|
|
231
|
+
}
|
|
232
|
+
return path.resolve(normalized);
|
|
233
|
+
}
|
|
234
|
+
export async function runSetupInitOrchestrator(options = {}, dependencies = {}) {
|
|
235
|
+
const inspectReadiness = dependencies.inspectReadiness ?? inspectSetupReadiness;
|
|
236
|
+
const setupCommunityServer = dependencies.setupCommunityServer ?? runCommunityServerSetup;
|
|
237
|
+
const startInstalledCockpit = dependencies.startInstalledCockpit ?? startCommunityNativeCockpit;
|
|
238
|
+
const stopInstalledCockpit = dependencies.stopInstalledCockpit ?? stopCommunityNativeCockpit;
|
|
239
|
+
const addTarget = dependencies.addTarget ?? runTargetAdd;
|
|
240
|
+
const authLogin = dependencies.authLogin ?? runAuthLogin;
|
|
241
|
+
const confirm = dependencies.confirm ?? promptConfirm;
|
|
242
|
+
const password = dependencies.password ?? promptPassword;
|
|
243
|
+
const input = dependencies.input ?? promptInput;
|
|
244
|
+
const select = dependencies.select ?? promptSelect;
|
|
245
|
+
const interactive = !options.yes && !options.json;
|
|
246
|
+
const directProgress = async (_label, action) => action();
|
|
247
|
+
const progress = interactive
|
|
248
|
+
? dependencies.progress ?? (process.stdout.isTTY === true ? withSpinner : directProgress)
|
|
249
|
+
: directProgress;
|
|
250
|
+
const requestedAgentAssetsAction = normalizeAgentAssetsAction(options.agentAssets);
|
|
251
|
+
const requestedPath = normalizeNonEmpty(options.path);
|
|
252
|
+
if (requestedPath && !parseSetupPath(requestedPath)) {
|
|
253
|
+
throw new Error('setup_init_path_invalid:choose_1_2_3_or_4');
|
|
254
|
+
}
|
|
255
|
+
if (interactive && !options.skipBanner) {
|
|
256
|
+
banner('AOPS Setup');
|
|
257
|
+
logInfo('Install directly here. For guided installation with any terminal AI agent, use `aops setup ai`.');
|
|
258
|
+
logInfo('Enter database secrets only in masked AOPS prompts; never paste them into chat.');
|
|
259
|
+
}
|
|
260
|
+
let selectedPath = parseSetupPath(requestedPath);
|
|
261
|
+
if (!selectedPath && interactive) {
|
|
262
|
+
const inferred = await inspectReadiness({
|
|
263
|
+
postgresConfig: options.postgresConfig,
|
|
264
|
+
postgresTls: options.postgresTls,
|
|
265
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
266
|
+
targetName: options.targetName,
|
|
267
|
+
instance: options.instance,
|
|
268
|
+
dataRoot: options.dataRoot,
|
|
269
|
+
sourceRoot: options.sourceRoot,
|
|
270
|
+
port: options.port,
|
|
271
|
+
agentAssetsProvider: dependencies.agentAssets,
|
|
272
|
+
timeoutMs: options.timeoutMs,
|
|
273
|
+
});
|
|
274
|
+
selectedPath = inferred.path.id ?? undefined;
|
|
275
|
+
if (!selectedPath) {
|
|
276
|
+
selectedPath = await select({
|
|
277
|
+
message: 'Choose an AOPS setup path:',
|
|
278
|
+
choices: SETUP_PATHS.map((entry) => ({
|
|
279
|
+
name: `${entry.number}. ${entry.title}`,
|
|
280
|
+
value: entry.id,
|
|
281
|
+
})),
|
|
282
|
+
default: 'native-external',
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const localSecurity = resolveSetupLocalSecurity(selectedPath, options.auth, options.exposure);
|
|
287
|
+
let effectiveApiBaseUrl = normalizeNonEmpty(options.apiBaseUrl);
|
|
288
|
+
let effectiveTargetName = normalizeNonEmpty(options.targetName);
|
|
289
|
+
if (selectedPath === 'cli-existing' && interactive) {
|
|
290
|
+
effectiveApiBaseUrl ??= normalizeNonEmpty(await input({
|
|
291
|
+
message: 'Existing AOPS Server URL:',
|
|
292
|
+
default: 'https://aops.example.com',
|
|
293
|
+
validate: (value) => {
|
|
294
|
+
try {
|
|
295
|
+
const parsed = new URL(value.trim());
|
|
296
|
+
return (['http:', 'https:'].includes(parsed.protocol) &&
|
|
297
|
+
!parsed.username && !parsed.password && !parsed.search && !parsed.hash &&
|
|
298
|
+
(parsed.pathname === '/' || parsed.pathname === '')) || 'Use an http(s) origin without credentials, query, fragment, or path.';
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
return 'Use a valid http(s) origin.';
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
}));
|
|
305
|
+
effectiveTargetName ??= normalizeNonEmpty(await input({
|
|
306
|
+
message: 'Name for this AOPS target:',
|
|
307
|
+
default: 'external',
|
|
308
|
+
validate: (value) => /^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$/.test(value.trim().toLowerCase())
|
|
309
|
+
? true
|
|
310
|
+
: 'Use 1-32 lowercase letters, digits, or hyphens.',
|
|
311
|
+
}));
|
|
312
|
+
}
|
|
313
|
+
let postgresTls = options.postgresTls;
|
|
314
|
+
if (selectedPath === 'native-external' && !postgresTls)
|
|
315
|
+
postgresTls = 'require';
|
|
316
|
+
let localPostgresHost = normalizeNonEmpty(options.localPostgresHost) ?? '127.0.0.1';
|
|
317
|
+
let localPostgresPort = options.localPostgresPort ?? 5432;
|
|
318
|
+
let localPostgresAdminUser = normalizeNonEmpty(options.localPostgresAdminUser)
|
|
319
|
+
?? defaultLocalPostgresAdminUser();
|
|
320
|
+
let localPostgresDatabase = normalizeNonEmpty(options.localPostgresDatabase)
|
|
321
|
+
?? defaultLocalPostgresDatabase(options.instance);
|
|
322
|
+
let localPostgresAppUser = normalizeNonEmpty(options.localPostgresAppUser)
|
|
323
|
+
?? localPostgresDatabase;
|
|
324
|
+
if (selectedPath === 'native-local' && interactive) {
|
|
325
|
+
localPostgresHost = await input({
|
|
326
|
+
message: 'Local PostgreSQL host (loopback only):',
|
|
327
|
+
default: localPostgresHost,
|
|
328
|
+
validate: (value) => ['localhost', '127.0.0.1', '::1'].includes(value.trim().toLowerCase())
|
|
329
|
+
|| /^127(?:\.\d{1,3}){3}$/.test(value.trim())
|
|
330
|
+
? true
|
|
331
|
+
: 'Use a loopback host such as 127.0.0.1 or localhost.',
|
|
332
|
+
});
|
|
333
|
+
localPostgresPort = Number(await input({
|
|
334
|
+
message: 'Local PostgreSQL port:',
|
|
335
|
+
default: String(localPostgresPort),
|
|
336
|
+
validate: (value) => {
|
|
337
|
+
const port = Number(value);
|
|
338
|
+
return Number.isSafeInteger(port) && port >= 1 && port <= 65_535 ? true : 'Use a TCP port from 1 to 65535.';
|
|
339
|
+
},
|
|
340
|
+
}));
|
|
341
|
+
localPostgresAdminUser = await input({
|
|
342
|
+
message: 'PostgreSQL administrator role:',
|
|
343
|
+
default: localPostgresAdminUser,
|
|
344
|
+
validate: validateLocalPostgresIdentifier,
|
|
345
|
+
});
|
|
346
|
+
localPostgresDatabase = await input({
|
|
347
|
+
message: 'New AOPS database name:',
|
|
348
|
+
default: localPostgresDatabase,
|
|
349
|
+
validate: validateLocalPostgresIdentifier,
|
|
350
|
+
});
|
|
351
|
+
localPostgresAppUser = await input({
|
|
352
|
+
message: 'New AOPS application role:',
|
|
353
|
+
default: localPostgresAppUser,
|
|
354
|
+
validate: validateLocalPostgresIdentifier,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
if (selectedPath && !['native-external', 'native-local'].includes(selectedPath) && options.postgresConfig) {
|
|
358
|
+
throw new Error('setup_init_postgres_config_only_valid_for_paths_1_or_3');
|
|
359
|
+
}
|
|
360
|
+
if (selectedPath && selectedPath !== 'native-external' && postgresTls) {
|
|
361
|
+
throw new Error('setup_init_postgres_tls_only_valid_for_path_1');
|
|
362
|
+
}
|
|
363
|
+
const localPostgresOptionsUsed = Boolean(options.localPostgresHost !== undefined || options.localPostgresPort !== undefined ||
|
|
364
|
+
options.localPostgresAdminUser !== undefined || options.localPostgresDatabase !== undefined ||
|
|
365
|
+
options.localPostgresAppUser !== undefined || options.localPostgresAdminNoPassword !== undefined);
|
|
366
|
+
if (selectedPath && selectedPath !== 'native-local' && localPostgresOptionsUsed) {
|
|
367
|
+
throw new Error('setup_init_local_postgres_options_only_valid_for_path_3');
|
|
368
|
+
}
|
|
369
|
+
if (selectedPath === 'cli-existing' && (options.noCatalog || options.catalogRelease || options.catalogIdempotencyKey)) {
|
|
370
|
+
throw new Error('setup_init_catalog_options_only_valid_for_server_paths_1_2_or_3');
|
|
371
|
+
}
|
|
372
|
+
if (options.noCatalog && (options.catalogRelease || options.catalogIdempotencyKey)) {
|
|
373
|
+
throw new Error('setup_init_catalog_mode_conflict:choose_default_catalog_or_--no-catalog');
|
|
374
|
+
}
|
|
375
|
+
let effectivePostgresConfig = options.postgresConfig;
|
|
376
|
+
let effectivePostgresTls = postgresTls;
|
|
377
|
+
let effectiveAuthProvider = localSecurity.authProvider;
|
|
378
|
+
let effectiveExposure = localSecurity.exposure;
|
|
379
|
+
const inspect = () => inspectReadiness({
|
|
380
|
+
path: selectedPath,
|
|
381
|
+
postgresConfig: effectivePostgresConfig,
|
|
382
|
+
postgresTls: effectivePostgresTls,
|
|
383
|
+
apiBaseUrl: effectiveApiBaseUrl,
|
|
384
|
+
targetName: effectiveTargetName,
|
|
385
|
+
instance: options.instance,
|
|
386
|
+
dataRoot: options.dataRoot,
|
|
387
|
+
sourceRoot: options.sourceRoot,
|
|
388
|
+
localPostgresHost,
|
|
389
|
+
localPostgresPort,
|
|
390
|
+
port: options.port,
|
|
391
|
+
auth: localSecurity.explicit ? effectiveAuthProvider : undefined,
|
|
392
|
+
exposure: localSecurity.explicit ? effectiveExposure : undefined,
|
|
393
|
+
agentAssetsProvider: dependencies.agentAssets,
|
|
394
|
+
timeoutMs: options.timeoutMs,
|
|
395
|
+
});
|
|
396
|
+
let initial = await inspect();
|
|
397
|
+
const initialServerEnv = initial.checks.find((check) => check.id === 'global-server-env');
|
|
398
|
+
if (!localSecurity.explicit &&
|
|
399
|
+
(initialServerEnv?.data?.authProvider === 'trusted-local')) {
|
|
400
|
+
effectiveAuthProvider = initialServerEnv.data.authProvider;
|
|
401
|
+
effectiveExposure = canonicalSetupExposure(effectiveAuthProvider);
|
|
402
|
+
}
|
|
403
|
+
const path3Env = initial.checks.find((check) => check.id === 'global-server-env');
|
|
404
|
+
if (selectedPath === 'native-local' && interactive && !options.postgresConfig &&
|
|
405
|
+
path3Env?.data?.blocking === true && typeof path3Env.data.path === 'string') {
|
|
406
|
+
const instance = normalizeNonEmpty(options.instance)?.toLowerCase() ?? 'default';
|
|
407
|
+
const suggested = path.join(path.dirname(path3Env.data.path), `aops.${instance}.local.server.env`);
|
|
408
|
+
effectivePostgresConfig = await input({
|
|
409
|
+
message: 'Private server env for this local PostgreSQL setup:',
|
|
410
|
+
default: suggested,
|
|
411
|
+
validate: (value) => path.isAbsolute(value.trim()) ? true : 'Use an absolute private env path.',
|
|
412
|
+
});
|
|
413
|
+
initial = await inspect();
|
|
414
|
+
}
|
|
415
|
+
const shouldApply = options.apply === true || (interactive && Boolean(selectedPath));
|
|
416
|
+
const installerPlan = createSetupInstallerPlan(options, selectedPath, localSecurity, initial, {
|
|
417
|
+
postgresConfig: effectivePostgresConfig,
|
|
418
|
+
postgresTls: effectivePostgresTls,
|
|
419
|
+
apiBaseUrl: effectiveApiBaseUrl,
|
|
420
|
+
targetName: effectiveTargetName,
|
|
421
|
+
localPostgresHost,
|
|
422
|
+
localPostgresPort,
|
|
423
|
+
localPostgresAdminUser,
|
|
424
|
+
localPostgresDatabase,
|
|
425
|
+
localPostgresAppUser,
|
|
426
|
+
}, dependencies.installerRelease, dependencies.managedLayout);
|
|
427
|
+
if (!shouldApply) {
|
|
428
|
+
if (options.json) {
|
|
429
|
+
console.log(JSON.stringify({
|
|
430
|
+
command: 'setup.init',
|
|
431
|
+
...initial,
|
|
432
|
+
installerPlan,
|
|
433
|
+
}, null, 2));
|
|
434
|
+
return initial;
|
|
435
|
+
}
|
|
436
|
+
if (!interactive || options.skipBanner || initial.status === 'ready')
|
|
437
|
+
printSetupReadiness(initial);
|
|
438
|
+
else
|
|
439
|
+
logInfo('Setup was not changed. Re-run with `--apply` when using an explicit non-interactive path.');
|
|
440
|
+
return initial;
|
|
441
|
+
}
|
|
442
|
+
if (!selectedPath)
|
|
443
|
+
throw new Error('setup_init_path_required_for_apply:choose_1_2_3_or_4');
|
|
444
|
+
if (options.planId !== undefined) {
|
|
445
|
+
const requestedPlanId = normalizeNonEmpty(options.planId);
|
|
446
|
+
if (!requestedPlanId || !/^sha256:[a-f0-9]{64}$/.test(requestedPlanId)) {
|
|
447
|
+
throw new Error('setup_init_plan_id_invalid');
|
|
448
|
+
}
|
|
449
|
+
if (requestedPlanId !== installerPlan.planId) {
|
|
450
|
+
throw new Error('setup_init_plan_changed:review_the_current_plan_before_apply');
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (dependencies.installerRelease) {
|
|
454
|
+
setupInstallerReleaseBinding(dependencies.installerRelease);
|
|
455
|
+
if (!dependencies.assertInstallerReleaseCurrent) {
|
|
456
|
+
throw new Error('setup_init_installer_release_apply_guard_unavailable');
|
|
457
|
+
}
|
|
458
|
+
await dependencies.assertInstallerReleaseCurrent(dependencies.installerRelease);
|
|
459
|
+
}
|
|
460
|
+
if ((requestedAgentAssetsAction === 'install' || requestedAgentAssetsAction === 'repair') &&
|
|
461
|
+
!dependencies.agentAssets?.apply) {
|
|
462
|
+
throw new Error('setup_init_agent_assets_contract_unavailable_task_136');
|
|
463
|
+
}
|
|
464
|
+
if (selectedPath === 'native-external' && !postgresTls) {
|
|
465
|
+
throw new Error('setup_init_postgres_tls_required_for_path_1');
|
|
466
|
+
}
|
|
467
|
+
let createPostgresSecret;
|
|
468
|
+
let serverEnvChanged = false;
|
|
469
|
+
if (selectedPath === 'native-container' && interactive) {
|
|
470
|
+
const passwordMode = await select({
|
|
471
|
+
message: 'Managed PostgreSQL password:',
|
|
472
|
+
choices: [
|
|
473
|
+
{ name: 'Generate a strong password automatically (recommended)', value: 'generate' },
|
|
474
|
+
{ name: 'Enter a custom password securely', value: 'custom' },
|
|
475
|
+
],
|
|
476
|
+
default: 'generate',
|
|
477
|
+
});
|
|
478
|
+
if (passwordMode === 'custom') {
|
|
479
|
+
const customPassword = await password({
|
|
480
|
+
message: 'PostgreSQL password:',
|
|
481
|
+
validate: validateManagedPostgresPassword,
|
|
482
|
+
});
|
|
483
|
+
const confirmedPassword = await password({
|
|
484
|
+
message: 'Confirm PostgreSQL password:',
|
|
485
|
+
validate: (value) => value === customPassword ? true : 'Passwords do not match.',
|
|
486
|
+
});
|
|
487
|
+
if (confirmedPassword !== customPassword)
|
|
488
|
+
throw new Error('setup_init_postgres_password_mismatch');
|
|
489
|
+
createPostgresSecret = () => customPassword;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
const localServerPath = selectedPath !== 'cli-existing';
|
|
493
|
+
const localApiBaseUrl = effectiveApiBaseUrl ?? `http://127.0.0.1:${options.port ?? 5900}`;
|
|
494
|
+
let officialCatalogRelease;
|
|
495
|
+
let officialCatalogReleaseSource;
|
|
496
|
+
if (localServerPath && !options.noCatalog && dependencies.officialCatalog) {
|
|
497
|
+
const selectedRelease = options.catalogRelease ?? options.agentAssetsRelease;
|
|
498
|
+
if (normalizeNonEmpty(selectedRelease)) {
|
|
499
|
+
officialCatalogRelease = resolveOfficialCatalogReleasePath(selectedRelease);
|
|
500
|
+
officialCatalogReleaseSource = options.catalogRelease ? 'explicit-catalog-release' : 'explicit-agent-assets-release';
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
const resolution = await dependencies.officialCatalog.resolveRelease({
|
|
504
|
+
sourceRoot: options.sourceRoot,
|
|
505
|
+
instance: options.instance,
|
|
506
|
+
dataRoot: options.dataRoot,
|
|
507
|
+
});
|
|
508
|
+
officialCatalogRelease = resolveOfficialCatalogReleasePath(resolution.fromRelease);
|
|
509
|
+
officialCatalogReleaseSource = resolution.source;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
else if (localServerPath && (options.catalogRelease || options.catalogIdempotencyKey) && !dependencies.officialCatalog) {
|
|
513
|
+
throw new Error('setup_init_official_catalog_contract_unavailable');
|
|
514
|
+
}
|
|
515
|
+
const blockingCheck = initial.checks.find((check) => check.data?.blocking === true);
|
|
516
|
+
if (blockingCheck) {
|
|
517
|
+
if (isCommunityDiagnosticV1(blockingCheck.data?.diagnostic)) {
|
|
518
|
+
throw new CommunityDiagnosticError(blockingCheck.data.diagnostic);
|
|
519
|
+
}
|
|
520
|
+
throw new Error('setup_init_install_state_requires_explicit_repair_or_reset');
|
|
521
|
+
}
|
|
522
|
+
const steps = [];
|
|
523
|
+
if (selectedPath === 'native-external') {
|
|
524
|
+
const envCheck = initial.checks.find((check) => check.id === 'global-server-env');
|
|
525
|
+
const envReady = envCheck?.state === 'ready';
|
|
526
|
+
if (interactive) {
|
|
527
|
+
if (!dependencies.setupServerEnv) {
|
|
528
|
+
throw new Error('setup_init_external_postgres_env_provider_unavailable');
|
|
529
|
+
}
|
|
530
|
+
const serverEnv = await dependencies.setupServerEnv({
|
|
531
|
+
root: options.sourceRoot,
|
|
532
|
+
envPath: options.postgresConfig,
|
|
533
|
+
auth: localSecurity.explicit ? effectiveAuthProvider : undefined,
|
|
534
|
+
skipBanner: true,
|
|
535
|
+
});
|
|
536
|
+
if (!serverEnv.ok || serverEnv.repoDialect !== 'pg') {
|
|
537
|
+
throw new Error('setup_init_external_postgres_env_not_ready');
|
|
538
|
+
}
|
|
539
|
+
effectivePostgresConfig = serverEnv.envPath;
|
|
540
|
+
if (localSecurity.explicit &&
|
|
541
|
+
serverEnv.authProvider &&
|
|
542
|
+
serverEnv.authProvider !== effectiveAuthProvider) {
|
|
543
|
+
throw new Error('setup_init_server_env_auth_provider_mismatch');
|
|
544
|
+
}
|
|
545
|
+
effectiveAuthProvider = serverEnv.authProvider ?? effectiveAuthProvider;
|
|
546
|
+
effectiveExposure = canonicalSetupExposure(effectiveAuthProvider);
|
|
547
|
+
serverEnvChanged = serverEnv.updated === true;
|
|
548
|
+
steps.push({
|
|
549
|
+
action: 'setup.server-env',
|
|
550
|
+
status: serverEnv.updated ? 'updated' : 'ready',
|
|
551
|
+
envPath: serverEnv.envPath,
|
|
552
|
+
authProvider: effectiveAuthProvider,
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
else if (!envReady &&
|
|
556
|
+
localSecurity.explicit &&
|
|
557
|
+
envCheck?.data?.postgresReady === true) {
|
|
558
|
+
if (!dependencies.setupServerEnv) {
|
|
559
|
+
throw new Error('setup_init_external_postgres_env_provider_unavailable');
|
|
560
|
+
}
|
|
561
|
+
const serverEnv = await dependencies.setupServerEnv({
|
|
562
|
+
root: options.sourceRoot,
|
|
563
|
+
envPath: options.postgresConfig ??
|
|
564
|
+
(typeof envCheck.data?.path === 'string' ? envCheck.data.path : undefined),
|
|
565
|
+
auth: effectiveAuthProvider,
|
|
566
|
+
yes: true,
|
|
567
|
+
skipBanner: true,
|
|
568
|
+
});
|
|
569
|
+
if (!serverEnv.ok ||
|
|
570
|
+
serverEnv.repoDialect !== 'pg' ||
|
|
571
|
+
serverEnv.authProvider !== effectiveAuthProvider) {
|
|
572
|
+
throw new Error('setup_init_external_postgres_env_not_ready');
|
|
573
|
+
}
|
|
574
|
+
effectivePostgresConfig = serverEnv.envPath;
|
|
575
|
+
effectiveExposure = canonicalSetupExposure(serverEnv.authProvider);
|
|
576
|
+
serverEnvChanged = serverEnv.updated === true;
|
|
577
|
+
steps.push({
|
|
578
|
+
action: 'setup.server-env',
|
|
579
|
+
status: serverEnv.updated ? 'updated' : 'ready',
|
|
580
|
+
envPath: serverEnv.envPath,
|
|
581
|
+
authProvider: serverEnv.authProvider,
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
else if (!envReady) {
|
|
585
|
+
throw new Error('setup_init_external_postgres_env_required:run_setup_server-env_first');
|
|
586
|
+
}
|
|
587
|
+
else if (!effectivePostgresConfig && typeof envCheck?.data?.path === 'string') {
|
|
588
|
+
effectivePostgresConfig = envCheck.data.path;
|
|
589
|
+
}
|
|
590
|
+
if (!effectivePostgresConfig || !effectivePostgresTls) {
|
|
591
|
+
throw new Error('setup_init_external_postgres_probe_configuration_missing');
|
|
592
|
+
}
|
|
593
|
+
const probe = dependencies.probeExternalPostgres ?? probeExternalPostgresConnection;
|
|
594
|
+
const testConnection = () => progress(`Testing PostgreSQL connection with ${effectivePostgresTls} TLS...`, () => probe({
|
|
595
|
+
configRef: effectivePostgresConfig,
|
|
596
|
+
tlsPolicy: effectivePostgresTls,
|
|
597
|
+
timeoutMs: options.timeoutMs,
|
|
598
|
+
}));
|
|
599
|
+
let connection;
|
|
600
|
+
try {
|
|
601
|
+
connection = await testConnection();
|
|
602
|
+
}
|
|
603
|
+
catch (error) {
|
|
604
|
+
if (!interactive || options.postgresTls || !isExternalPostgresTlsProbeError(error))
|
|
605
|
+
throw error;
|
|
606
|
+
effectivePostgresTls = await select({
|
|
607
|
+
message: 'PostgreSQL TLS connection failed. Choose how to retry:',
|
|
608
|
+
choices: [
|
|
609
|
+
{
|
|
610
|
+
name: 'require',
|
|
611
|
+
value: 'require',
|
|
612
|
+
description: 'Keep encrypted transport without CA verification; fix PostgreSQL TLS support if this still fails.',
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
name: 'verify-full',
|
|
616
|
+
value: 'verify-full',
|
|
617
|
+
description: 'Use certificate and hostname verification with a trusted CA certificate.',
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
name: 'disable',
|
|
621
|
+
value: 'disable',
|
|
622
|
+
description: 'Retry without encryption only when you explicitly accept an unencrypted connection.',
|
|
623
|
+
},
|
|
624
|
+
],
|
|
625
|
+
default: 'require',
|
|
626
|
+
});
|
|
627
|
+
connection = await testConnection();
|
|
628
|
+
}
|
|
629
|
+
steps.push({ action: 'setup.postgres-connection', ...connection });
|
|
630
|
+
if (interactive) {
|
|
631
|
+
logSuccess(`PostgreSQL connection verified (${connection.transport}, server ${connection.serverMajor}).`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (selectedPath === 'native-local') {
|
|
635
|
+
const localCheck = initial.checks.find((check) => check.id === 'local-postgresql');
|
|
636
|
+
if (localCheck?.state !== 'ready') {
|
|
637
|
+
throw new Error('setup_init_local_postgres_not_ready:inspect_readiness_next_actions');
|
|
638
|
+
}
|
|
639
|
+
const envCheck = initial.checks.find((check) => check.id === 'global-server-env');
|
|
640
|
+
if (envCheck?.state === 'ready') {
|
|
641
|
+
effectivePostgresConfig = String(envCheck.data?.path ?? '') || undefined;
|
|
642
|
+
effectivePostgresTls = 'disable';
|
|
643
|
+
if (!localSecurity.explicit &&
|
|
644
|
+
(envCheck.data?.authProvider === 'trusted-local')) {
|
|
645
|
+
effectiveAuthProvider = envCheck.data.authProvider;
|
|
646
|
+
effectiveExposure = canonicalSetupExposure(effectiveAuthProvider);
|
|
647
|
+
}
|
|
648
|
+
steps.push({
|
|
649
|
+
action: 'setup.local-postgres',
|
|
650
|
+
status: 'already-configured',
|
|
651
|
+
host: localPostgresHost,
|
|
652
|
+
port: localPostgresPort,
|
|
653
|
+
envPath: effectivePostgresConfig,
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
else if (localSecurity.explicit &&
|
|
657
|
+
envCheck?.data?.postgresReady === true) {
|
|
658
|
+
if (!dependencies.setupServerEnv) {
|
|
659
|
+
throw new Error('setup_init_local_postgres_env_provider_unavailable');
|
|
660
|
+
}
|
|
661
|
+
const serverEnv = await dependencies.setupServerEnv({
|
|
662
|
+
root: options.sourceRoot,
|
|
663
|
+
envPath: effectivePostgresConfig ??
|
|
664
|
+
(typeof envCheck.data?.path === 'string' ? envCheck.data.path : undefined),
|
|
665
|
+
auth: effectiveAuthProvider,
|
|
666
|
+
yes: true,
|
|
667
|
+
skipBanner: true,
|
|
668
|
+
});
|
|
669
|
+
if (!serverEnv.ok ||
|
|
670
|
+
serverEnv.repoDialect !== 'pg' ||
|
|
671
|
+
serverEnv.authProvider !== effectiveAuthProvider) {
|
|
672
|
+
throw new Error('setup_init_local_postgres_env_not_ready');
|
|
673
|
+
}
|
|
674
|
+
effectivePostgresConfig = serverEnv.envPath;
|
|
675
|
+
effectivePostgresTls = 'disable';
|
|
676
|
+
effectiveExposure = canonicalSetupExposure(serverEnv.authProvider);
|
|
677
|
+
serverEnvChanged = serverEnv.updated === true;
|
|
678
|
+
steps.push({
|
|
679
|
+
action: 'setup.server-env',
|
|
680
|
+
status: serverEnv.updated ? 'updated' : 'ready',
|
|
681
|
+
envPath: serverEnv.envPath,
|
|
682
|
+
authProvider: serverEnv.authProvider,
|
|
683
|
+
});
|
|
684
|
+
steps.push({
|
|
685
|
+
action: 'setup.local-postgres',
|
|
686
|
+
status: 'already-configured',
|
|
687
|
+
host: localPostgresHost,
|
|
688
|
+
port: localPostgresPort,
|
|
689
|
+
envPath: serverEnv.envPath,
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
let adminPassword = process.env.AOPS_LOCAL_POSTGRES_ADMIN_PASSWORD ?? '';
|
|
694
|
+
const passwordValidation = validateLocalPostgresAdminPassword(adminPassword);
|
|
695
|
+
if (passwordValidation !== true)
|
|
696
|
+
throw new Error('setup_init_local_postgres_admin_password_invalid');
|
|
697
|
+
if (interactive) {
|
|
698
|
+
adminPassword = await password({
|
|
699
|
+
message: 'Existing PostgreSQL administrator password (leave blank only for local trust auth):',
|
|
700
|
+
validate: validateLocalPostgresAdminPassword,
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
else if (!adminPassword && options.localPostgresAdminNoPassword !== true) {
|
|
704
|
+
throw new Error('setup_init_local_postgres_admin_password_required:use_private_environment_or_--local-postgres-admin-no-password');
|
|
705
|
+
}
|
|
706
|
+
const provision = dependencies.provisionLocalPostgres ?? provisionLocalPostgres;
|
|
707
|
+
let provisioned;
|
|
708
|
+
try {
|
|
709
|
+
provisioned = await progress('Creating the local AOPS PostgreSQL role and database...', () => provision({
|
|
710
|
+
host: localPostgresHost,
|
|
711
|
+
port: localPostgresPort,
|
|
712
|
+
adminUser: localPostgresAdminUser,
|
|
713
|
+
adminPassword,
|
|
714
|
+
database: localPostgresDatabase,
|
|
715
|
+
appUser: localPostgresAppUser,
|
|
716
|
+
connectTimeoutMs: options.timeoutMs,
|
|
717
|
+
}));
|
|
718
|
+
}
|
|
719
|
+
finally {
|
|
720
|
+
adminPassword = '';
|
|
721
|
+
delete process.env.AOPS_LOCAL_POSTGRES_ADMIN_PASSWORD;
|
|
722
|
+
}
|
|
723
|
+
const { connectionUrl, ...safeProvisioned } = provisioned;
|
|
724
|
+
if (!dependencies.setupServerEnv) {
|
|
725
|
+
throw new Error('setup_init_local_postgres_env_provider_unavailable');
|
|
726
|
+
}
|
|
727
|
+
const serverEnv = await dependencies.setupServerEnv({
|
|
728
|
+
root: options.sourceRoot,
|
|
729
|
+
envPath: effectivePostgresConfig,
|
|
730
|
+
repoUrl: connectionUrl,
|
|
731
|
+
auth: localSecurity.explicit ? effectiveAuthProvider : undefined,
|
|
732
|
+
yes: true,
|
|
733
|
+
skipBanner: true,
|
|
734
|
+
});
|
|
735
|
+
if (!serverEnv.ok || serverEnv.repoDialect !== 'pg') {
|
|
736
|
+
throw new Error('setup_init_local_postgres_env_not_ready');
|
|
737
|
+
}
|
|
738
|
+
effectivePostgresConfig = serverEnv.envPath;
|
|
739
|
+
effectivePostgresTls = 'disable';
|
|
740
|
+
if (localSecurity.explicit &&
|
|
741
|
+
serverEnv.authProvider &&
|
|
742
|
+
serverEnv.authProvider !== effectiveAuthProvider) {
|
|
743
|
+
throw new Error('setup_init_server_env_auth_provider_mismatch');
|
|
744
|
+
}
|
|
745
|
+
effectiveAuthProvider = serverEnv.authProvider ?? effectiveAuthProvider;
|
|
746
|
+
effectiveExposure = canonicalSetupExposure(effectiveAuthProvider);
|
|
747
|
+
serverEnvChanged = serverEnv.updated === true;
|
|
748
|
+
steps.push({
|
|
749
|
+
action: 'setup.local-postgres',
|
|
750
|
+
...safeProvisioned,
|
|
751
|
+
envPath: serverEnv.envPath,
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
if (selectedPath === 'native-external' || selectedPath === 'native-container' || selectedPath === 'native-local') {
|
|
756
|
+
const installationCheck = initial.checks.find((check) => check.id === 'installation-state');
|
|
757
|
+
const installationReady = installationCheck?.state === 'ready';
|
|
758
|
+
const installationPresent = installationReady || installationCheck?.data?.installed === true;
|
|
759
|
+
const installedSecurityKnown = (installationCheck?.data?.authProvider === 'trusted-local') &&
|
|
760
|
+
(installationCheck?.data?.exposure === 'loopback');
|
|
761
|
+
const installedSecurityMatches = installedSecurityKnown
|
|
762
|
+
? (installationCheck?.data?.authProvider === effectiveAuthProvider &&
|
|
763
|
+
installationCheck?.data?.exposure === effectiveExposure)
|
|
764
|
+
: !localSecurity.explicit;
|
|
765
|
+
const hostReady = initial.checks.find((check) => check.id === 'host')?.state === 'ready';
|
|
766
|
+
let reuseRunningServer = false;
|
|
767
|
+
if (installationReady && hostReady && !serverEnvChanged && installedSecurityMatches) {
|
|
768
|
+
try {
|
|
769
|
+
const verifyInstalledApplication = dependencies.assertInstalledApplicationCurrent ??
|
|
770
|
+
assertInstalledApplicationCurrent;
|
|
771
|
+
verifyInstalledApplication({
|
|
772
|
+
instanceName: options.instance,
|
|
773
|
+
dataRoot: options.dataRoot,
|
|
774
|
+
sourceRoot: options.sourceRoot ??
|
|
775
|
+
(dependencies.resolveDefaultSourceRoot ?? resolveCommunityNativeDefaultSourceRoot)(),
|
|
776
|
+
});
|
|
777
|
+
const installedPlan = await progress('Checking the running AOPS server database migrations...', () => (dependencies.planInstalledMigration ?? planCommunityNativeInstalledMigration)({
|
|
778
|
+
instanceName: options.instance,
|
|
779
|
+
dataRoot: options.dataRoot,
|
|
780
|
+
}));
|
|
781
|
+
if (installedPlan.planning.migrationPlan.action === 'verify-only') {
|
|
782
|
+
reuseRunningServer = true;
|
|
783
|
+
steps.push({
|
|
784
|
+
action: 'community-server.setup',
|
|
785
|
+
status: 'already-running-current',
|
|
786
|
+
migrationAction: 'verify-only',
|
|
787
|
+
acceptedPlanSha256: installedPlan.planning.acceptedPlanSha256,
|
|
788
|
+
});
|
|
789
|
+
if (interactive)
|
|
790
|
+
logSuccess('Running AOPS server database schema is already current.');
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
catch (error) {
|
|
794
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
795
|
+
const applicationChanged = reason === 'community_native_selected_source_changed' ||
|
|
796
|
+
/^community_native_prior_application_(?:source|build)_drift$/.test(reason) ||
|
|
797
|
+
/^community_native_(?:source|build)_drift(?::|$)/.test(reason);
|
|
798
|
+
if (!applicationChanged)
|
|
799
|
+
throw error;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
if (!reuseRunningServer && installationPresent) {
|
|
803
|
+
await progress('Stopping Cockpit for setup changes...', () => stopInstalledCockpit({
|
|
804
|
+
instanceName: options.instance,
|
|
805
|
+
dataRoot: options.dataRoot,
|
|
806
|
+
}));
|
|
807
|
+
steps.push({ action: 'community-cockpit.stop-for-setup', status: 'applied' });
|
|
808
|
+
await progress('Stopping the local AOPS server for setup changes...', () => (dependencies.stopInstalledServer ?? stopCommunityNativeInstall)({
|
|
809
|
+
instanceName: options.instance,
|
|
810
|
+
dataRoot: options.dataRoot,
|
|
811
|
+
timeoutMs: options.timeoutMs,
|
|
812
|
+
}));
|
|
813
|
+
steps.push({ action: 'community-server.stop-for-setup', status: 'applied' });
|
|
814
|
+
}
|
|
815
|
+
if (!reuseRunningServer) {
|
|
816
|
+
let lifecycleResult;
|
|
817
|
+
const reportedStages = new Set();
|
|
818
|
+
await progress('Preparing PostgreSQL, verifying migrations, and starting AOPS server...', () => setupCommunityServer({
|
|
819
|
+
runtime: 'native',
|
|
820
|
+
postgres: selectedPath === 'native-external' || selectedPath === 'native-local'
|
|
821
|
+
? 'external'
|
|
822
|
+
: selectedPath === 'native-container'
|
|
823
|
+
? 'container'
|
|
824
|
+
: undefined,
|
|
825
|
+
postgresConfig: selectedPath === 'native-external' || selectedPath === 'native-local'
|
|
826
|
+
? effectivePostgresConfig
|
|
827
|
+
: undefined,
|
|
828
|
+
postgresTls: selectedPath === 'native-external' || selectedPath === 'native-local'
|
|
829
|
+
? effectivePostgresTls
|
|
830
|
+
: undefined,
|
|
831
|
+
auth: effectiveAuthProvider,
|
|
832
|
+
exposure: effectiveExposure,
|
|
833
|
+
instance: options.instance,
|
|
834
|
+
dataRoot: options.dataRoot,
|
|
835
|
+
sourceRoot: options.sourceRoot,
|
|
836
|
+
port: options.port,
|
|
837
|
+
detach: true,
|
|
838
|
+
createPostgresSecret: selectedPath === 'native-container' ? createPostgresSecret : undefined,
|
|
839
|
+
apply: true,
|
|
840
|
+
silent: true,
|
|
841
|
+
progressSink: interactive
|
|
842
|
+
? (event) => {
|
|
843
|
+
if (reportedStages.has(event.stage))
|
|
844
|
+
return;
|
|
845
|
+
reportedStages.add(event.stage);
|
|
846
|
+
logInfo(` ${event.message}`);
|
|
847
|
+
}
|
|
848
|
+
: undefined,
|
|
849
|
+
resultSink: (result) => { lifecycleResult = result; },
|
|
850
|
+
}));
|
|
851
|
+
steps.push({ action: 'community-server.setup', status: 'applied', result: lifecycleResult ?? null });
|
|
852
|
+
if (interactive)
|
|
853
|
+
printMigrationVerification(lifecycleResult);
|
|
854
|
+
}
|
|
855
|
+
const cockpit = await progress('Starting AOPS Cockpit on its separate loopback port...', () => startInstalledCockpit({
|
|
856
|
+
instanceName: options.instance,
|
|
857
|
+
dataRoot: options.dataRoot,
|
|
858
|
+
}));
|
|
859
|
+
steps.push({
|
|
860
|
+
action: 'community-cockpit.start',
|
|
861
|
+
status: cockpit.action,
|
|
862
|
+
origin: cockpit.origin,
|
|
863
|
+
serverOrigin: cockpit.serverOrigin,
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
const targetCheck = initial.checks.find((check) => check.id === 'target-login');
|
|
868
|
+
const targetName = effectiveTargetName ??
|
|
869
|
+
(typeof targetCheck?.data?.name === 'string' ? targetCheck.data.name : undefined);
|
|
870
|
+
const apiBaseUrl = effectiveApiBaseUrl ??
|
|
871
|
+
(typeof targetCheck?.data?.apiBaseUrl === 'string' ? targetCheck.data.apiBaseUrl : undefined);
|
|
872
|
+
const targetReady = initial.checks.find((check) => check.id === 'target-login')?.state === 'ready';
|
|
873
|
+
if (!targetReady && apiBaseUrl && targetName) {
|
|
874
|
+
let targetResult;
|
|
875
|
+
await addTarget({
|
|
876
|
+
name: targetName,
|
|
877
|
+
apiBaseUrl,
|
|
878
|
+
authProvider: options.targetAuthProvider,
|
|
879
|
+
tlsPolicy: options.targetTlsPolicy,
|
|
880
|
+
use: true,
|
|
881
|
+
apply: true,
|
|
882
|
+
quiet: options.json === true,
|
|
883
|
+
resultSink: (result) => { targetResult = result; },
|
|
884
|
+
});
|
|
885
|
+
steps.push({ action: 'target.add', status: 'applied', result: targetResult ?? null });
|
|
886
|
+
effectiveApiBaseUrl = apiBaseUrl;
|
|
887
|
+
effectiveTargetName = targetName;
|
|
888
|
+
}
|
|
889
|
+
else if (!targetReady) {
|
|
890
|
+
throw new Error('setup_init_existing_server_target_required:provide_--target-name_and_--api-base-url');
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
if (localServerPath && options.noCatalog) {
|
|
894
|
+
steps.push({
|
|
895
|
+
action: 'setup.catalog.skip',
|
|
896
|
+
status: 'skipped',
|
|
897
|
+
reason: '--no-catalog',
|
|
898
|
+
coreClientAssetsAffected: false,
|
|
899
|
+
existingCatalogRowsDeleted: false,
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
else if (localServerPath && dependencies.officialCatalog && officialCatalogRelease) {
|
|
903
|
+
const catalog = await progress('Installing the official AOPS catalog...', () => dependencies.officialCatalog.reconcile({
|
|
904
|
+
fromRelease: officialCatalogRelease,
|
|
905
|
+
apiBaseUrl: localApiBaseUrl,
|
|
906
|
+
timeoutMs: options.timeoutMs,
|
|
907
|
+
idempotencyKey: options.catalogIdempotencyKey,
|
|
908
|
+
}));
|
|
909
|
+
steps.push({
|
|
910
|
+
action: 'setup.catalog.reconcile',
|
|
911
|
+
status: catalog.mutation,
|
|
912
|
+
scopeSlug: catalog.scopeSlug,
|
|
913
|
+
releaseSetSha256: catalog.releaseSetSha256,
|
|
914
|
+
receiptId: catalog.receiptId ?? null,
|
|
915
|
+
releaseSource: officialCatalogReleaseSource,
|
|
916
|
+
historyDeleteCount: catalog.historyDeleteCount,
|
|
917
|
+
activationEffects: catalog.activationEffects,
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
let result = await progress('Checking AOPS server health and setup readiness...', inspect);
|
|
921
|
+
const agentAssetsCheck = result.checks.find((check) => check.id === 'agent-assets');
|
|
922
|
+
let agentAssetsAction = requestedAgentAssetsAction;
|
|
923
|
+
if (agentAssetsCheck?.state === 'ready') {
|
|
924
|
+
steps.push({ action: 'assets.status', status: 'ready', target: 'all' });
|
|
925
|
+
agentAssetsAction = 'skip';
|
|
926
|
+
}
|
|
927
|
+
else if (!agentAssetsAction && dependencies.agentAssets?.apply) {
|
|
928
|
+
const recommendedAction = agentAssetsCheck?.data?.recommendedAction === 'repair' ? 'repair' : 'install';
|
|
929
|
+
if (interactive) {
|
|
930
|
+
logInfo(`Codex gateway: ${SETUP_AGENT_ASSETS_GATEWAYS.codex}`);
|
|
931
|
+
logInfo(`Claude gateway: ${SETUP_AGENT_ASSETS_GATEWAYS.claude}`);
|
|
932
|
+
logInfo(`Setup will ${recommendedAction} the verified AOPS core and gateway for every registered runtime.`);
|
|
933
|
+
logInfo('Rich mounted-domain guides and discipline references will be available; setup will not select a working discipline for you.');
|
|
934
|
+
}
|
|
935
|
+
agentAssetsAction = recommendedAction;
|
|
936
|
+
}
|
|
937
|
+
if (agentAssetsAction === 'install' || agentAssetsAction === 'repair') {
|
|
938
|
+
if (!dependencies.agentAssets?.apply) {
|
|
939
|
+
throw new Error('setup_init_agent_assets_contract_unavailable_task_136');
|
|
940
|
+
}
|
|
941
|
+
let fromRelease = options.agentAssetsRelease ?? officialCatalogRelease;
|
|
942
|
+
if (agentAssetsAction === 'install' && !normalizeNonEmpty(fromRelease) && dependencies.agentAssets.resolveRelease) {
|
|
943
|
+
const resolution = await dependencies.agentAssets.resolveRelease({
|
|
944
|
+
sourceRoot: options.sourceRoot,
|
|
945
|
+
instance: options.instance,
|
|
946
|
+
dataRoot: options.dataRoot,
|
|
947
|
+
});
|
|
948
|
+
fromRelease = resolution.fromRelease;
|
|
949
|
+
}
|
|
950
|
+
const appliedAssets = await progress('Installing global AOPS agent gateways...', () => applySetupAgentAssets(dependencies.agentAssets, {
|
|
951
|
+
action: agentAssetsAction,
|
|
952
|
+
fromRelease: agentAssetsAction === 'install'
|
|
953
|
+
? resolveAgentAssetsReleasePath(fromRelease)
|
|
954
|
+
: undefined,
|
|
955
|
+
}));
|
|
956
|
+
steps.push({ action: `assets.${agentAssetsAction}`, status: appliedAssets.state, target: 'all' });
|
|
957
|
+
result = await inspect();
|
|
958
|
+
}
|
|
959
|
+
if (interactive && result.checks.find((check) => check.id === 'target-login')?.state === 'action-required') {
|
|
960
|
+
if (await confirm({ message: 'Login to the selected target now?', default: true })) {
|
|
961
|
+
await authLogin({ apiBaseUrl: effectiveApiBaseUrl, target: effectiveTargetName });
|
|
962
|
+
steps.push({ action: 'auth.login', status: process.exitCode === 1 ? 'failed' : 'applied' });
|
|
963
|
+
result = await inspect();
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
if (options.json) {
|
|
967
|
+
console.log(JSON.stringify({
|
|
968
|
+
command: 'setup.init',
|
|
969
|
+
mutationFree: false,
|
|
970
|
+
applied: {
|
|
971
|
+
path: selectedPath,
|
|
972
|
+
mode: options.resume === true ? 'resume' : 'apply',
|
|
973
|
+
planId: installerPlan.planId,
|
|
974
|
+
...(localServerPath
|
|
975
|
+
? {
|
|
976
|
+
security: {
|
|
977
|
+
authProvider: effectiveAuthProvider,
|
|
978
|
+
exposure: effectiveExposure,
|
|
979
|
+
},
|
|
980
|
+
}
|
|
981
|
+
: {}),
|
|
982
|
+
steps,
|
|
983
|
+
},
|
|
984
|
+
readiness: result,
|
|
985
|
+
}, null, 2));
|
|
986
|
+
return result;
|
|
987
|
+
}
|
|
988
|
+
printSetupReadiness(result);
|
|
989
|
+
return result;
|
|
990
|
+
}
|