@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,1127 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { banner, logError, logInfo, logSuccess } from '@aopslabs/xf-cli-ui';
|
|
7
|
+
import { getHostRegistrationsDir, listInstalledHostRegistrations, materializeHostRegistrationManifest, mergeHostRegistrationsIntoConfig, normalizeHostRegistrationManifest, unregisterHostRegistration, writeHostRegistration, } from '@aopslabs/aops-host-registration';
|
|
8
|
+
import { getAopsServerEnvPath, inferAopsRepoDialect, readAopsServerEnvConfig, redactAopsRepoUrl, writeAopsServerEnvConfig, } from '@aopslabs/aops-runtime-config';
|
|
9
|
+
import { createCliApiClientFromOptions, fetchCliHealth } from '../utils/api.js';
|
|
10
|
+
import { applyCommonOptions, compactPayload } from '../utils/command.js';
|
|
11
|
+
import { ensureDestructiveWrite } from '../utils/hosted-sugar.js';
|
|
12
|
+
import { parseJsonInput, requireApiState } from '../utils/agent-gateway.js';
|
|
13
|
+
const HOST_LOG_LEVELS = ['debug', 'info', 'warn', 'error', 'fatal'];
|
|
14
|
+
const HOST_DATABASE_RESET_CONFIRM_TEXT = 'I understand all data will be lost';
|
|
15
|
+
function normalizeNonEmpty(value) {
|
|
16
|
+
if (typeof value !== 'string')
|
|
17
|
+
return undefined;
|
|
18
|
+
const trimmed = value.trim();
|
|
19
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
20
|
+
}
|
|
21
|
+
function expandHomePath(input) {
|
|
22
|
+
const trimmed = input.trim();
|
|
23
|
+
if (!trimmed)
|
|
24
|
+
return trimmed;
|
|
25
|
+
if (trimmed === '~')
|
|
26
|
+
return os.homedir();
|
|
27
|
+
if (trimmed.startsWith('~/') || trimmed.startsWith('~\\')) {
|
|
28
|
+
return path.join(os.homedir(), trimmed.slice(2));
|
|
29
|
+
}
|
|
30
|
+
return trimmed;
|
|
31
|
+
}
|
|
32
|
+
function resolveHostEnvPath(options) {
|
|
33
|
+
const envPath = normalizeNonEmpty(options.envPath);
|
|
34
|
+
if (!envPath)
|
|
35
|
+
return getAopsServerEnvPath(process.env);
|
|
36
|
+
return path.resolve(process.cwd(), expandHomePath(envPath));
|
|
37
|
+
}
|
|
38
|
+
function normalizeHostLogLevel(value) {
|
|
39
|
+
const normalized = normalizeNonEmpty(value)?.toLowerCase();
|
|
40
|
+
if (!normalized)
|
|
41
|
+
return undefined;
|
|
42
|
+
if (HOST_LOG_LEVELS.includes(normalized)) {
|
|
43
|
+
return normalized;
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
function resolveRepoUrlEnvName(value) {
|
|
48
|
+
const normalized = normalizeNonEmpty(value);
|
|
49
|
+
if (!normalized)
|
|
50
|
+
return undefined;
|
|
51
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(normalized)) {
|
|
52
|
+
throw new Error('Invalid --repo-url-env name. Use a valid environment variable name.');
|
|
53
|
+
}
|
|
54
|
+
return normalized;
|
|
55
|
+
}
|
|
56
|
+
function printHostConfigResult(payload, options) {
|
|
57
|
+
if (options.json) {
|
|
58
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
62
|
+
}
|
|
63
|
+
function printHostDatabaseResult(payload, options) {
|
|
64
|
+
if (options.json) {
|
|
65
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
69
|
+
}
|
|
70
|
+
function collectRepeatedOption(value, previous = []) {
|
|
71
|
+
const normalized = normalizeNonEmpty(value);
|
|
72
|
+
return normalized ? [...previous, normalized] : previous;
|
|
73
|
+
}
|
|
74
|
+
function toNonEmptyStringArray(value) {
|
|
75
|
+
if (!Array.isArray(value))
|
|
76
|
+
return undefined;
|
|
77
|
+
const normalized = value
|
|
78
|
+
.map((entry) => normalizeNonEmpty(entry))
|
|
79
|
+
.filter((entry) => Boolean(entry));
|
|
80
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
81
|
+
}
|
|
82
|
+
function normalizeHostDatabaseResetMode(value) {
|
|
83
|
+
const normalized = normalizeNonEmpty(value)?.toLowerCase();
|
|
84
|
+
if (!normalized)
|
|
85
|
+
return undefined;
|
|
86
|
+
if (normalized === 'drop-only')
|
|
87
|
+
return 'drop-only';
|
|
88
|
+
if (normalized === 'drop-and-recreate')
|
|
89
|
+
return 'drop-and-recreate';
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
function buildHostDatabaseResetInput(options) {
|
|
93
|
+
const mode = normalizeHostDatabaseResetMode(options.mode);
|
|
94
|
+
if (options.mode && !mode) {
|
|
95
|
+
throw new Error('Invalid --mode. Use one of: drop-only, drop-and-recreate');
|
|
96
|
+
}
|
|
97
|
+
return compactPayload({
|
|
98
|
+
confirmText: normalizeNonEmpty(options.confirmText) ??
|
|
99
|
+
HOST_DATABASE_RESET_CONFIRM_TEXT,
|
|
100
|
+
mode,
|
|
101
|
+
includeAuthTables: options.includeAuthTables === true,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function normalizeHostDatabaseBackupRestoreMode(value) {
|
|
105
|
+
const normalized = normalizeNonEmpty(value)?.toLowerCase();
|
|
106
|
+
if (!normalized)
|
|
107
|
+
return undefined;
|
|
108
|
+
if (normalized === 'truncate-and-insert')
|
|
109
|
+
return 'truncate-and-insert';
|
|
110
|
+
if (normalized === 'insert-only')
|
|
111
|
+
return 'insert-only';
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
function resolveHostOutputPath(value) {
|
|
115
|
+
const normalized = normalizeNonEmpty(value);
|
|
116
|
+
if (!normalized)
|
|
117
|
+
return undefined;
|
|
118
|
+
return path.resolve(process.cwd(), normalized);
|
|
119
|
+
}
|
|
120
|
+
function buildHostDatabaseBackupExportInput(options) {
|
|
121
|
+
return compactPayload({
|
|
122
|
+
includeAuthTables: options.includeAuthTables === true,
|
|
123
|
+
tables: toNonEmptyStringArray(options.table),
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function resolveBackupPayloadFromInput(options) {
|
|
127
|
+
const inputPath = normalizeNonEmpty(options.input);
|
|
128
|
+
const inputJson = normalizeNonEmpty(options.inputJson);
|
|
129
|
+
if (inputPath && inputJson) {
|
|
130
|
+
throw new Error('Provide only one of --input or --input-json.');
|
|
131
|
+
}
|
|
132
|
+
if (inputPath) {
|
|
133
|
+
return JSON.parse(fs.readFileSync(path.resolve(process.cwd(), inputPath), 'utf8'));
|
|
134
|
+
}
|
|
135
|
+
if (inputJson) {
|
|
136
|
+
return parseJsonInput(inputJson, '--input-json');
|
|
137
|
+
}
|
|
138
|
+
throw new Error('Missing backup input. Use --input or --input-json.');
|
|
139
|
+
}
|
|
140
|
+
function buildHostDatabaseBackupRestoreInput(options) {
|
|
141
|
+
const mode = normalizeHostDatabaseBackupRestoreMode(options.mode);
|
|
142
|
+
if (options.mode && !mode) {
|
|
143
|
+
throw new Error('Invalid --mode. Use one of: truncate-and-insert, insert-only');
|
|
144
|
+
}
|
|
145
|
+
return compactPayload({
|
|
146
|
+
confirmText: normalizeNonEmpty(options.confirmText) ??
|
|
147
|
+
HOST_DATABASE_RESET_CONFIRM_TEXT,
|
|
148
|
+
mode,
|
|
149
|
+
backup: resolveBackupPayloadFromInput(options),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
export const nativePgCommandRuntime = {
|
|
153
|
+
async runProcess(tool, args) {
|
|
154
|
+
return await new Promise((resolve, reject) => {
|
|
155
|
+
const child = spawn(tool, args, {
|
|
156
|
+
stdio: 'inherit',
|
|
157
|
+
shell: false,
|
|
158
|
+
});
|
|
159
|
+
child.on('error', (error) => reject(error));
|
|
160
|
+
child.on('close', (exitCode, signal) => {
|
|
161
|
+
resolve({
|
|
162
|
+
exitCode,
|
|
163
|
+
signal,
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
function resolvePgBinDir(value) {
|
|
170
|
+
const normalized = normalizeNonEmpty(value);
|
|
171
|
+
if (!normalized)
|
|
172
|
+
return undefined;
|
|
173
|
+
return path.resolve(process.cwd(), expandHomePath(normalized));
|
|
174
|
+
}
|
|
175
|
+
function resolveNativePgToolCommand(tool, pgBinDir) {
|
|
176
|
+
if (!pgBinDir)
|
|
177
|
+
return tool;
|
|
178
|
+
const executable = process.platform === 'win32' ? `${tool}.exe` : tool;
|
|
179
|
+
return path.join(pgBinDir, executable);
|
|
180
|
+
}
|
|
181
|
+
function redactNativePgArgs(args, redactedRepoUrl) {
|
|
182
|
+
return args.map((arg) => {
|
|
183
|
+
if (arg.startsWith('--dbname='))
|
|
184
|
+
return `--dbname=${redactedRepoUrl}`;
|
|
185
|
+
return arg;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
function resolveHostPgRepoTarget(options) {
|
|
189
|
+
const explicitRepoUrl = normalizeNonEmpty(options.repoUrl);
|
|
190
|
+
if (explicitRepoUrl) {
|
|
191
|
+
if (inferAopsRepoDialect(explicitRepoUrl) !== 'pg') {
|
|
192
|
+
throw new Error('PG-native dump commands require a PostgreSQL repo URL.');
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
repoUrl: explicitRepoUrl,
|
|
196
|
+
redactedRepoUrl: redactAopsRepoUrl(explicitRepoUrl),
|
|
197
|
+
repoUrlSource: 'option',
|
|
198
|
+
envPath: null,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
const envPath = normalizeNonEmpty(options.envPath)
|
|
202
|
+
? path.resolve(process.cwd(), expandHomePath(String(options.envPath)))
|
|
203
|
+
: undefined;
|
|
204
|
+
const hostEnv = readAopsServerEnvConfig(process.env, envPath);
|
|
205
|
+
if (!hostEnv.repoUrl) {
|
|
206
|
+
throw new Error('Missing PostgreSQL repo URL. Configure the selected host env with `aops-cli setup server-env` first.');
|
|
207
|
+
}
|
|
208
|
+
if (hostEnv.repoDialect !== 'pg') {
|
|
209
|
+
throw new Error('PG-native dump commands require the configured host repo URL to be PostgreSQL.');
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
repoUrl: hostEnv.repoUrl,
|
|
213
|
+
redactedRepoUrl: hostEnv.redactedRepoUrl ?? redactAopsRepoUrl(hostEnv.repoUrl),
|
|
214
|
+
repoUrlSource: 'host-env',
|
|
215
|
+
envPath: hostEnv.path,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function assertMutuallyExclusiveDataShape(options) {
|
|
219
|
+
if (options.schemaOnly === true && options.dataOnly === true) {
|
|
220
|
+
throw new Error('Use only one of --schema-only or --data-only.');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function buildHostDatabaseDumpExportInvocation(options) {
|
|
224
|
+
assertMutuallyExclusiveDataShape(options);
|
|
225
|
+
const outputPath = resolveHostOutputPath(options.output);
|
|
226
|
+
if (!outputPath) {
|
|
227
|
+
throw new Error('Missing --output. PG-native dump export writes a .dump file to disk.');
|
|
228
|
+
}
|
|
229
|
+
const pgBinDir = resolvePgBinDir(options.pgBinDir);
|
|
230
|
+
const repoTarget = resolveHostPgRepoTarget(options);
|
|
231
|
+
const args = [
|
|
232
|
+
`--dbname=${repoTarget.repoUrl}`,
|
|
233
|
+
'--format=custom',
|
|
234
|
+
'--file',
|
|
235
|
+
outputPath,
|
|
236
|
+
'--no-owner',
|
|
237
|
+
'--no-privileges',
|
|
238
|
+
];
|
|
239
|
+
if (options.schemaOnly === true)
|
|
240
|
+
args.push('--schema-only');
|
|
241
|
+
if (options.dataOnly === true)
|
|
242
|
+
args.push('--data-only');
|
|
243
|
+
for (const tableName of toNonEmptyStringArray(options.table) ?? []) {
|
|
244
|
+
args.push('--table', tableName);
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
...repoTarget,
|
|
248
|
+
tool: resolveNativePgToolCommand('pg_dump', pgBinDir),
|
|
249
|
+
args,
|
|
250
|
+
redactedArgs: redactNativePgArgs(args, repoTarget.redactedRepoUrl),
|
|
251
|
+
outputPath,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function buildHostDatabaseDumpRestoreInvocation(options) {
|
|
255
|
+
assertMutuallyExclusiveDataShape(options);
|
|
256
|
+
const inputPath = resolveHostOutputPath(options.input);
|
|
257
|
+
if (!inputPath) {
|
|
258
|
+
throw new Error('Missing --input. PG-native dump restore requires a dump file path.');
|
|
259
|
+
}
|
|
260
|
+
if (!fs.existsSync(inputPath)) {
|
|
261
|
+
throw new Error(`Dump input not found: ${inputPath}`);
|
|
262
|
+
}
|
|
263
|
+
const pgBinDir = resolvePgBinDir(options.pgBinDir);
|
|
264
|
+
const repoTarget = resolveHostPgRepoTarget(options);
|
|
265
|
+
const args = [
|
|
266
|
+
`--dbname=${repoTarget.repoUrl}`,
|
|
267
|
+
'--no-owner',
|
|
268
|
+
'--no-privileges',
|
|
269
|
+
];
|
|
270
|
+
if (options.clean === true) {
|
|
271
|
+
args.push('--clean', '--if-exists');
|
|
272
|
+
}
|
|
273
|
+
if (options.schemaOnly === true)
|
|
274
|
+
args.push('--schema-only');
|
|
275
|
+
if (options.dataOnly === true)
|
|
276
|
+
args.push('--data-only');
|
|
277
|
+
for (const tableName of toNonEmptyStringArray(options.table) ?? []) {
|
|
278
|
+
args.push('--table', tableName);
|
|
279
|
+
}
|
|
280
|
+
args.push(inputPath);
|
|
281
|
+
return {
|
|
282
|
+
...repoTarget,
|
|
283
|
+
tool: resolveNativePgToolCommand('pg_restore', pgBinDir),
|
|
284
|
+
args,
|
|
285
|
+
redactedArgs: redactNativePgArgs(args, repoTarget.redactedRepoUrl),
|
|
286
|
+
inputPath,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function formatNativePgRunnerError(error, tool) {
|
|
290
|
+
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
|
|
291
|
+
return `Required PostgreSQL client tool not found: ${tool}. Install PostgreSQL client tools or pass --pg-bin-dir.`;
|
|
292
|
+
}
|
|
293
|
+
return error instanceof Error ? error.message : String(error);
|
|
294
|
+
}
|
|
295
|
+
function resolveWarmupTimeoutMs(options, shouldWarmup, shouldReset) {
|
|
296
|
+
if (typeof options.timeoutMs === 'number' && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0) {
|
|
297
|
+
return options.timeoutMs;
|
|
298
|
+
}
|
|
299
|
+
if (shouldWarmup || shouldReset)
|
|
300
|
+
return 120_000;
|
|
301
|
+
return options.timeoutMs;
|
|
302
|
+
}
|
|
303
|
+
function buildHostDiagnosticsPath(options) {
|
|
304
|
+
const query = new URLSearchParams();
|
|
305
|
+
if (options.reset === true)
|
|
306
|
+
query.set('reset', '1');
|
|
307
|
+
if (options.warmup === true)
|
|
308
|
+
query.set('warmup', '1');
|
|
309
|
+
const search = query.toString();
|
|
310
|
+
return search ? `/api/host-admin/plugins?${search}` : '/api/host-admin/plugins';
|
|
311
|
+
}
|
|
312
|
+
function applyHostRegistrationOptions(cmd) {
|
|
313
|
+
return cmd.option('--registrations-dir <path>', 'Host registrations directory (default: AOPS_HOST_REGISTRATIONS_DIR or ~/.aops/host-registrations)');
|
|
314
|
+
}
|
|
315
|
+
function resolveHostRegistrationsDir(options) {
|
|
316
|
+
return getHostRegistrationsDir({
|
|
317
|
+
registrationsDir: options.registrationsDir,
|
|
318
|
+
processEnv: process.env,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
function printHostRegistrationResult(payload, options) {
|
|
322
|
+
if (options.json) {
|
|
323
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
327
|
+
}
|
|
328
|
+
function requireCommunityRegistrationJsonPath(options) {
|
|
329
|
+
const from = options.from?.trim();
|
|
330
|
+
if (!from)
|
|
331
|
+
throw new Error('Missing registration source. Use --from /path/to/host-registration.json.');
|
|
332
|
+
const filePath = path.resolve(process.cwd(), from);
|
|
333
|
+
if (path.extname(filePath).toLowerCase() !== '.json') {
|
|
334
|
+
throw new Error('Community host registration accepts JSON files only.');
|
|
335
|
+
}
|
|
336
|
+
const stats = fs.lstatSync(filePath);
|
|
337
|
+
if (!stats.isFile() || stats.isSymbolicLink()) {
|
|
338
|
+
throw new Error(`Community host registration must be a regular JSON file: ${filePath}`);
|
|
339
|
+
}
|
|
340
|
+
return fs.realpathSync(filePath);
|
|
341
|
+
}
|
|
342
|
+
function loadCommunityHostRegistrationJson(filePath) {
|
|
343
|
+
let parsed;
|
|
344
|
+
try {
|
|
345
|
+
parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
throw new Error(`Host registration JSON parse failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
349
|
+
}
|
|
350
|
+
const materialized = materializeHostRegistrationManifest(normalizeHostRegistrationManifest(parsed), path.dirname(filePath));
|
|
351
|
+
return normalizeHostRegistrationManifest({
|
|
352
|
+
...materialized,
|
|
353
|
+
provenance: {
|
|
354
|
+
...materialized.provenance,
|
|
355
|
+
source: filePath,
|
|
356
|
+
sourceType: 'file',
|
|
357
|
+
registeredAt: new Date().toISOString(),
|
|
358
|
+
},
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
export async function runHostRegister(options = {}) {
|
|
362
|
+
const interactive = !options.yes && !options.json;
|
|
363
|
+
const source = requireCommunityRegistrationJsonPath(options);
|
|
364
|
+
const registrationsDir = resolveHostRegistrationsDir(options);
|
|
365
|
+
if (interactive) {
|
|
366
|
+
banner('AOPS Host Register');
|
|
367
|
+
logInfo(`Registry: ${registrationsDir}`);
|
|
368
|
+
logInfo(`Source: ${source}`);
|
|
369
|
+
}
|
|
370
|
+
try {
|
|
371
|
+
const manifest = loadCommunityHostRegistrationJson(source);
|
|
372
|
+
const filePath = writeHostRegistration(manifest, {
|
|
373
|
+
registrationsDir,
|
|
374
|
+
processEnv: process.env,
|
|
375
|
+
});
|
|
376
|
+
if (!options.json)
|
|
377
|
+
logSuccess(`Registered ${manifest.domain}.`);
|
|
378
|
+
printHostRegistrationResult({
|
|
379
|
+
ok: true,
|
|
380
|
+
domain: manifest.domain,
|
|
381
|
+
displayName: manifest.displayName ?? null,
|
|
382
|
+
packageName: manifest.packageName ?? null,
|
|
383
|
+
filePath,
|
|
384
|
+
registrationsDir,
|
|
385
|
+
manifest,
|
|
386
|
+
}, options);
|
|
387
|
+
}
|
|
388
|
+
catch (error) {
|
|
389
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
390
|
+
logError(`Registration failed: ${message}`);
|
|
391
|
+
process.exitCode = 1;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
export async function runHostRegistrations(options = {}) {
|
|
395
|
+
const interactive = !options.yes && !options.json;
|
|
396
|
+
const registrationsDir = resolveHostRegistrationsDir(options);
|
|
397
|
+
if (interactive) {
|
|
398
|
+
banner('AOPS Host Registrations');
|
|
399
|
+
logInfo(`Registry: ${registrationsDir}`);
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
const registrations = listInstalledHostRegistrations({
|
|
403
|
+
registrationsDir,
|
|
404
|
+
processEnv: process.env,
|
|
405
|
+
});
|
|
406
|
+
if (!options.json)
|
|
407
|
+
logSuccess(`Loaded ${registrations.length} registration(s).`);
|
|
408
|
+
printHostRegistrationResult({
|
|
409
|
+
ok: true,
|
|
410
|
+
registrationsDir,
|
|
411
|
+
count: registrations.length,
|
|
412
|
+
registrations: registrations.map((entry) => ({
|
|
413
|
+
domain: entry.domain,
|
|
414
|
+
filePath: entry.filePath,
|
|
415
|
+
displayName: entry.manifest.displayName ?? null,
|
|
416
|
+
packageName: entry.manifest.packageName ?? null,
|
|
417
|
+
description: entry.manifest.description ?? null,
|
|
418
|
+
manifestProviderCount: entry.manifest.manifestProviders?.length ?? 0,
|
|
419
|
+
pluginCount: entry.manifest.plugins?.length ?? 0,
|
|
420
|
+
sourceCount: entry.manifest.sources?.length ?? 0,
|
|
421
|
+
})),
|
|
422
|
+
}, options);
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
426
|
+
logError(`Failed to load registrations: ${message}`);
|
|
427
|
+
process.exitCode = 1;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
export async function runHostUnregister(options = {}) {
|
|
431
|
+
const interactive = !options.yes && !options.json;
|
|
432
|
+
const domain = options.domain?.trim().toLowerCase();
|
|
433
|
+
if (!domain) {
|
|
434
|
+
logError('Missing --domain.');
|
|
435
|
+
process.exitCode = 1;
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
const registrationsDir = resolveHostRegistrationsDir(options);
|
|
439
|
+
if (interactive) {
|
|
440
|
+
banner('AOPS Host Unregister');
|
|
441
|
+
logInfo(`Registry: ${registrationsDir}`);
|
|
442
|
+
logInfo(`Domain: ${domain}`);
|
|
443
|
+
}
|
|
444
|
+
const removed = unregisterHostRegistration(domain, {
|
|
445
|
+
registrationsDir,
|
|
446
|
+
processEnv: process.env,
|
|
447
|
+
});
|
|
448
|
+
if (!removed) {
|
|
449
|
+
logError(`Registration not found: ${domain}`);
|
|
450
|
+
process.exitCode = 1;
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (!options.json)
|
|
454
|
+
logSuccess(`Unregistered ${domain}.`);
|
|
455
|
+
printHostRegistrationResult({
|
|
456
|
+
ok: true,
|
|
457
|
+
domain,
|
|
458
|
+
registrationsDir,
|
|
459
|
+
removed: true,
|
|
460
|
+
}, options);
|
|
461
|
+
}
|
|
462
|
+
export async function runHostExplainRegistration(options = {}) {
|
|
463
|
+
const interactive = !options.yes && !options.json;
|
|
464
|
+
const domain = options.domain?.trim().toLowerCase();
|
|
465
|
+
if (!domain) {
|
|
466
|
+
logError('Missing --domain.');
|
|
467
|
+
process.exitCode = 1;
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
const registrationsDir = resolveHostRegistrationsDir(options);
|
|
471
|
+
const registrations = listInstalledHostRegistrations({
|
|
472
|
+
registrationsDir,
|
|
473
|
+
processEnv: process.env,
|
|
474
|
+
});
|
|
475
|
+
const entry = registrations.find((item) => item.domain === domain);
|
|
476
|
+
if (!entry) {
|
|
477
|
+
logError(`Registration not found: ${domain}`);
|
|
478
|
+
process.exitCode = 1;
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (interactive) {
|
|
482
|
+
banner('AOPS Host Registration');
|
|
483
|
+
logInfo(`Registry: ${registrationsDir}`);
|
|
484
|
+
logInfo(`Domain: ${domain}`);
|
|
485
|
+
}
|
|
486
|
+
const projected = mergeHostRegistrationsIntoConfig({}, [entry.manifest]);
|
|
487
|
+
if (!options.json)
|
|
488
|
+
logSuccess(`Explained ${domain} registration.`);
|
|
489
|
+
printHostRegistrationResult({
|
|
490
|
+
ok: true,
|
|
491
|
+
registrationsDir,
|
|
492
|
+
filePath: entry.filePath,
|
|
493
|
+
manifest: entry.manifest,
|
|
494
|
+
projectedConfig: projected,
|
|
495
|
+
}, options);
|
|
496
|
+
}
|
|
497
|
+
export async function runHostHealth(options = {}) {
|
|
498
|
+
const interactive = !options.yes && !options.json;
|
|
499
|
+
const apiState = await createCliApiClientFromOptions(options);
|
|
500
|
+
if (interactive) {
|
|
501
|
+
banner('AOPS Host Health');
|
|
502
|
+
logInfo(`API: ${apiState.baseUrl}`);
|
|
503
|
+
}
|
|
504
|
+
try {
|
|
505
|
+
const payload = await fetchCliHealth(apiState, { timeoutMs: options.timeoutMs });
|
|
506
|
+
if (!options.json)
|
|
507
|
+
logSuccess('Host is healthy.');
|
|
508
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
509
|
+
}
|
|
510
|
+
catch (error) {
|
|
511
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
512
|
+
logError(`Health check failed: ${message}`);
|
|
513
|
+
process.exitCode = 1;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
export async function runHostConfigShow(options = {}) {
|
|
517
|
+
const interactive = !options.yes && !options.json;
|
|
518
|
+
const envPath = resolveHostEnvPath(options);
|
|
519
|
+
const snapshot = readAopsServerEnvConfig(process.env, envPath);
|
|
520
|
+
if (interactive) {
|
|
521
|
+
banner('AOPS Host Config');
|
|
522
|
+
logInfo(`Host env: ${snapshot.path}`);
|
|
523
|
+
}
|
|
524
|
+
if (!options.json) {
|
|
525
|
+
logSuccess(snapshot.exists ? 'Loaded local host env config.' : 'Local host env config is not created yet.');
|
|
526
|
+
}
|
|
527
|
+
printHostConfigResult({
|
|
528
|
+
ok: true,
|
|
529
|
+
action: 'host.config.show',
|
|
530
|
+
envPath: snapshot.path,
|
|
531
|
+
exists: snapshot.exists,
|
|
532
|
+
repoUrlPresent: Boolean(snapshot.repoUrl),
|
|
533
|
+
repoDialect: snapshot.repoDialect,
|
|
534
|
+
redactedRepoUrl: snapshot.redactedRepoUrl,
|
|
535
|
+
logLevel: snapshot.hostSettings.logLevel,
|
|
536
|
+
next: {
|
|
537
|
+
setRepo: 'aops-cli setup server-env',
|
|
538
|
+
setLogLevel: 'aops-cli host config set --log-level <level>',
|
|
539
|
+
},
|
|
540
|
+
}, options);
|
|
541
|
+
}
|
|
542
|
+
export async function runHostConfigSet(options = {}) {
|
|
543
|
+
const interactive = !options.yes && !options.json;
|
|
544
|
+
let repoUrlEnv;
|
|
545
|
+
try {
|
|
546
|
+
repoUrlEnv = resolveRepoUrlEnvName(options.repoUrlEnv);
|
|
547
|
+
}
|
|
548
|
+
catch (error) {
|
|
549
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
550
|
+
process.exitCode = 1;
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (normalizeNonEmpty(options.repoUrl) && repoUrlEnv) {
|
|
554
|
+
logError('Provide only one internal repo URL source.');
|
|
555
|
+
process.exitCode = 1;
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
const repoUrl = normalizeNonEmpty(options.repoUrl) ??
|
|
559
|
+
(repoUrlEnv ? normalizeNonEmpty(process.env[repoUrlEnv]) : undefined);
|
|
560
|
+
const logLevel = normalizeHostLogLevel(options.logLevel);
|
|
561
|
+
if (repoUrlEnv && !repoUrl) {
|
|
562
|
+
logError(`Environment variable ${repoUrlEnv} is empty or missing.`);
|
|
563
|
+
process.exitCode = 1;
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
if (!repoUrl && options.logLevel && !logLevel) {
|
|
567
|
+
logError(`Invalid --log-level. Use one of: ${HOST_LOG_LEVELS.join(', ')}`);
|
|
568
|
+
process.exitCode = 1;
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
if (!repoUrl && !logLevel) {
|
|
572
|
+
logError('Nothing to update. Provide --repo-url-env and/or --log-level.');
|
|
573
|
+
process.exitCode = 1;
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
const envPath = resolveHostEnvPath(options);
|
|
577
|
+
if (interactive) {
|
|
578
|
+
banner('AOPS Host Config Set');
|
|
579
|
+
logInfo(`Host env: ${envPath}`);
|
|
580
|
+
if (repoUrl)
|
|
581
|
+
logInfo(`Repo: ${redactAopsRepoUrl(repoUrl)}`);
|
|
582
|
+
if (logLevel)
|
|
583
|
+
logInfo(`Log level: ${logLevel}`);
|
|
584
|
+
}
|
|
585
|
+
const written = writeAopsServerEnvConfig({
|
|
586
|
+
...(repoUrl ? { repoUrl } : {}),
|
|
587
|
+
...(logLevel ? { logLevel } : {}),
|
|
588
|
+
}, process.env, envPath);
|
|
589
|
+
if (!options.json) {
|
|
590
|
+
logSuccess('Updated local host env config. Restart aops-server to apply changes.');
|
|
591
|
+
}
|
|
592
|
+
printHostConfigResult({
|
|
593
|
+
ok: true,
|
|
594
|
+
action: 'host.config.set',
|
|
595
|
+
envPath: written.path,
|
|
596
|
+
exists: written.exists,
|
|
597
|
+
repoUrlPresent: Boolean(written.repoUrl),
|
|
598
|
+
repoDialect: written.repoUrl ? inferAopsRepoDialect(written.repoUrl) : null,
|
|
599
|
+
redactedRepoUrl: written.redactedRepoUrl,
|
|
600
|
+
logLevel: written.hostSettings.logLevel,
|
|
601
|
+
restartRequired: true,
|
|
602
|
+
}, options);
|
|
603
|
+
}
|
|
604
|
+
export async function runHostDiagnostics(options = {}) {
|
|
605
|
+
const interactive = !options.yes && !options.json;
|
|
606
|
+
const apiState = await requireApiState(options);
|
|
607
|
+
if (!apiState)
|
|
608
|
+
return;
|
|
609
|
+
const shouldReset = options.reset === true;
|
|
610
|
+
const shouldWarmup = options.warmup === true;
|
|
611
|
+
const requestTimeoutMs = resolveWarmupTimeoutMs(options, shouldWarmup, shouldReset);
|
|
612
|
+
const path = buildHostDiagnosticsPath(options);
|
|
613
|
+
if (interactive) {
|
|
614
|
+
banner('AOPS Host Diagnostics');
|
|
615
|
+
logInfo(`API: ${apiState.baseUrl}`);
|
|
616
|
+
if (shouldReset)
|
|
617
|
+
logInfo('Reset: enabled');
|
|
618
|
+
if (shouldWarmup)
|
|
619
|
+
logInfo('Warmup: enabled');
|
|
620
|
+
if (requestTimeoutMs && (shouldWarmup || shouldReset))
|
|
621
|
+
logInfo(`Timeout: ${requestTimeoutMs}ms`);
|
|
622
|
+
}
|
|
623
|
+
try {
|
|
624
|
+
const payload = await apiState.client.fetchJson(path, {
|
|
625
|
+
method: 'GET',
|
|
626
|
+
timeoutMs: requestTimeoutMs,
|
|
627
|
+
});
|
|
628
|
+
if (!options.json)
|
|
629
|
+
logSuccess('Host diagnostics loaded.');
|
|
630
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
631
|
+
}
|
|
632
|
+
catch (error) {
|
|
633
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
634
|
+
logError(`Failed to load host diagnostics: ${message}`);
|
|
635
|
+
process.exitCode = 1;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
export async function runHostDatabaseStatus(options = {}) {
|
|
639
|
+
const interactive = !options.yes && !options.json;
|
|
640
|
+
const apiState = await requireApiState(options);
|
|
641
|
+
if (!apiState)
|
|
642
|
+
return;
|
|
643
|
+
if (interactive) {
|
|
644
|
+
banner('AOPS Host Database Status');
|
|
645
|
+
logInfo(`API: ${apiState.baseUrl}`);
|
|
646
|
+
}
|
|
647
|
+
try {
|
|
648
|
+
const payload = await apiState.client.fetchJson('/api/aops/settings/database/status', {
|
|
649
|
+
method: 'GET',
|
|
650
|
+
timeoutMs: options.timeoutMs,
|
|
651
|
+
});
|
|
652
|
+
if (!options.json)
|
|
653
|
+
logSuccess('Host database status loaded.');
|
|
654
|
+
printHostDatabaseResult(payload, options);
|
|
655
|
+
}
|
|
656
|
+
catch (error) {
|
|
657
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
658
|
+
logError(`Failed to load host database status: ${message}`);
|
|
659
|
+
process.exitCode = 1;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
export async function runHostDatabaseReset(options = {}) {
|
|
663
|
+
const interactive = !options.yes && !options.json;
|
|
664
|
+
try {
|
|
665
|
+
ensureDestructiveWrite({
|
|
666
|
+
apply: options.apply,
|
|
667
|
+
confirm: options.confirm,
|
|
668
|
+
preview: options.preview,
|
|
669
|
+
}, 'This command resets hosted database tables.');
|
|
670
|
+
}
|
|
671
|
+
catch (error) {
|
|
672
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
673
|
+
process.exitCode = 1;
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
let input;
|
|
677
|
+
try {
|
|
678
|
+
input = buildHostDatabaseResetInput(options);
|
|
679
|
+
}
|
|
680
|
+
catch (error) {
|
|
681
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
682
|
+
process.exitCode = 1;
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
if (options.preview) {
|
|
686
|
+
const payload = {
|
|
687
|
+
ok: true,
|
|
688
|
+
action: 'host.database.reset.preview',
|
|
689
|
+
surface: '/api/aops/settings/database/reset',
|
|
690
|
+
destructive: true,
|
|
691
|
+
input,
|
|
692
|
+
next: {
|
|
693
|
+
apply: 'aops-cli host database reset --mode drop-and-recreate --apply --confirm',
|
|
694
|
+
},
|
|
695
|
+
};
|
|
696
|
+
if (!options.json)
|
|
697
|
+
logSuccess('Host database reset preview ready.');
|
|
698
|
+
printHostDatabaseResult(payload, options);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
const apiState = await requireApiState(options);
|
|
702
|
+
if (!apiState)
|
|
703
|
+
return;
|
|
704
|
+
if (interactive) {
|
|
705
|
+
banner('AOPS Host Database Reset');
|
|
706
|
+
logInfo(`API: ${apiState.baseUrl}`);
|
|
707
|
+
logInfo(`Mode: ${String(input.mode ?? 'drop-only')}`);
|
|
708
|
+
if (input.includeAuthTables === true) {
|
|
709
|
+
logInfo('Include auth tables: yes');
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
try {
|
|
713
|
+
const payload = await apiState.client.fetchJson('/api/aops/settings/database/reset', {
|
|
714
|
+
method: 'POST',
|
|
715
|
+
body: input,
|
|
716
|
+
timeoutMs: options.timeoutMs,
|
|
717
|
+
});
|
|
718
|
+
if (!options.json)
|
|
719
|
+
logSuccess('Host database reset completed.');
|
|
720
|
+
printHostDatabaseResult(payload, options);
|
|
721
|
+
}
|
|
722
|
+
catch (error) {
|
|
723
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
724
|
+
logError(`Host database reset failed: ${message}`);
|
|
725
|
+
process.exitCode = 1;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
export async function runHostDatabaseBackupExport(options = {}) {
|
|
729
|
+
const interactive = !options.yes && !options.json;
|
|
730
|
+
const apiState = await requireApiState(options);
|
|
731
|
+
if (!apiState)
|
|
732
|
+
return;
|
|
733
|
+
const input = buildHostDatabaseBackupExportInput(options);
|
|
734
|
+
const outputPath = resolveHostOutputPath(options.output);
|
|
735
|
+
if (interactive) {
|
|
736
|
+
banner('AOPS Host Database Backup Export');
|
|
737
|
+
logInfo(`API: ${apiState.baseUrl}`);
|
|
738
|
+
if (outputPath)
|
|
739
|
+
logInfo(`Output: ${outputPath}`);
|
|
740
|
+
}
|
|
741
|
+
try {
|
|
742
|
+
const payload = await apiState.client.fetchJson('/api/aops/settings/database/backup/export', {
|
|
743
|
+
method: 'POST',
|
|
744
|
+
body: input,
|
|
745
|
+
timeoutMs: options.timeoutMs,
|
|
746
|
+
});
|
|
747
|
+
const backup = payload?.data ?? payload;
|
|
748
|
+
if (outputPath) {
|
|
749
|
+
fs.writeFileSync(outputPath, `${JSON.stringify(backup, null, 2)}\n`, 'utf8');
|
|
750
|
+
const response = {
|
|
751
|
+
ok: true,
|
|
752
|
+
action: 'host.database.backup.export',
|
|
753
|
+
outputPath,
|
|
754
|
+
input,
|
|
755
|
+
};
|
|
756
|
+
if (!options.json)
|
|
757
|
+
logSuccess('Host database backup exported.');
|
|
758
|
+
printHostDatabaseResult(response, options);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
if (!options.json)
|
|
762
|
+
logSuccess('Host database backup exported.');
|
|
763
|
+
printHostDatabaseResult(backup, options);
|
|
764
|
+
}
|
|
765
|
+
catch (error) {
|
|
766
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
767
|
+
logError(`Host database backup export failed: ${message}`);
|
|
768
|
+
process.exitCode = 1;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
export async function runHostDatabaseBackupRestore(options = {}) {
|
|
772
|
+
const interactive = !options.yes && !options.json;
|
|
773
|
+
try {
|
|
774
|
+
ensureDestructiveWrite({
|
|
775
|
+
apply: options.apply,
|
|
776
|
+
confirm: options.confirm,
|
|
777
|
+
preview: options.preview,
|
|
778
|
+
}, 'This command restores hosted database state.');
|
|
779
|
+
}
|
|
780
|
+
catch (error) {
|
|
781
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
782
|
+
process.exitCode = 1;
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
let input;
|
|
786
|
+
try {
|
|
787
|
+
input = buildHostDatabaseBackupRestoreInput(options);
|
|
788
|
+
}
|
|
789
|
+
catch (error) {
|
|
790
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
791
|
+
process.exitCode = 1;
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
if (options.preview) {
|
|
795
|
+
const payload = {
|
|
796
|
+
ok: true,
|
|
797
|
+
action: 'host.database.backup.restore.preview',
|
|
798
|
+
surface: '/api/aops/settings/database/backup/restore',
|
|
799
|
+
destructive: true,
|
|
800
|
+
input,
|
|
801
|
+
next: {
|
|
802
|
+
apply: 'aops-cli host database backup restore --input <backup.json> --apply --confirm',
|
|
803
|
+
},
|
|
804
|
+
};
|
|
805
|
+
if (!options.json)
|
|
806
|
+
logSuccess('Host database backup restore preview ready.');
|
|
807
|
+
printHostDatabaseResult(payload, options);
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
const apiState = await requireApiState(options);
|
|
811
|
+
if (!apiState)
|
|
812
|
+
return;
|
|
813
|
+
if (interactive) {
|
|
814
|
+
banner('AOPS Host Database Backup Restore');
|
|
815
|
+
logInfo(`API: ${apiState.baseUrl}`);
|
|
816
|
+
logInfo(`Mode: ${String(input.mode ?? 'truncate-and-insert')}`);
|
|
817
|
+
}
|
|
818
|
+
try {
|
|
819
|
+
const payload = await apiState.client.fetchJson('/api/aops/settings/database/backup/restore', {
|
|
820
|
+
method: 'POST',
|
|
821
|
+
body: input,
|
|
822
|
+
timeoutMs: options.timeoutMs,
|
|
823
|
+
});
|
|
824
|
+
if (!options.json)
|
|
825
|
+
logSuccess('Host database backup restore completed.');
|
|
826
|
+
printHostDatabaseResult(payload, options);
|
|
827
|
+
}
|
|
828
|
+
catch (error) {
|
|
829
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
830
|
+
logError(`Host database backup restore failed: ${message}`);
|
|
831
|
+
process.exitCode = 1;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
export async function runHostDatabaseDumpExport(options = {}) {
|
|
835
|
+
const interactive = !options.yes && !options.json;
|
|
836
|
+
let invocation;
|
|
837
|
+
try {
|
|
838
|
+
invocation = buildHostDatabaseDumpExportInvocation(options);
|
|
839
|
+
}
|
|
840
|
+
catch (error) {
|
|
841
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
842
|
+
process.exitCode = 1;
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
if (interactive) {
|
|
846
|
+
banner('AOPS Host Database Dump Export');
|
|
847
|
+
logInfo(`Repo: ${invocation.redactedRepoUrl}`);
|
|
848
|
+
logInfo(`Output: ${invocation.outputPath}`);
|
|
849
|
+
logInfo(`Tool: ${invocation.tool}`);
|
|
850
|
+
}
|
|
851
|
+
try {
|
|
852
|
+
const result = await nativePgCommandRuntime.runProcess(invocation.tool, invocation.args);
|
|
853
|
+
if (result.exitCode !== 0) {
|
|
854
|
+
throw new Error(`${path.basename(invocation.tool)} exited with code ${String(result.exitCode ?? 'null')}.`);
|
|
855
|
+
}
|
|
856
|
+
const payload = {
|
|
857
|
+
ok: true,
|
|
858
|
+
action: 'host.database.dump.export',
|
|
859
|
+
format: 'pg-custom',
|
|
860
|
+
tool: invocation.tool,
|
|
861
|
+
args: invocation.redactedArgs,
|
|
862
|
+
outputPath: invocation.outputPath,
|
|
863
|
+
repoUrl: invocation.redactedRepoUrl,
|
|
864
|
+
repoUrlSource: invocation.repoUrlSource,
|
|
865
|
+
envPath: invocation.envPath,
|
|
866
|
+
};
|
|
867
|
+
if (!options.json)
|
|
868
|
+
logSuccess('PG-native dump export completed.');
|
|
869
|
+
printHostDatabaseResult(payload, options);
|
|
870
|
+
}
|
|
871
|
+
catch (error) {
|
|
872
|
+
logError(`PG-native dump export failed: ${formatNativePgRunnerError(error, invocation.tool)}`);
|
|
873
|
+
process.exitCode = 1;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
export async function runHostDatabaseDumpRestore(options = {}) {
|
|
877
|
+
const interactive = !options.yes && !options.json;
|
|
878
|
+
try {
|
|
879
|
+
ensureDestructiveWrite({
|
|
880
|
+
apply: options.apply,
|
|
881
|
+
confirm: options.confirm,
|
|
882
|
+
preview: options.preview,
|
|
883
|
+
}, 'This command restores database state using pg_restore.');
|
|
884
|
+
}
|
|
885
|
+
catch (error) {
|
|
886
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
887
|
+
process.exitCode = 1;
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
let invocation;
|
|
891
|
+
try {
|
|
892
|
+
invocation = buildHostDatabaseDumpRestoreInvocation(options);
|
|
893
|
+
}
|
|
894
|
+
catch (error) {
|
|
895
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
896
|
+
process.exitCode = 1;
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
if (options.preview) {
|
|
900
|
+
const payload = {
|
|
901
|
+
ok: true,
|
|
902
|
+
action: 'host.database.dump.restore.preview',
|
|
903
|
+
destructive: true,
|
|
904
|
+
tool: invocation.tool,
|
|
905
|
+
args: invocation.redactedArgs,
|
|
906
|
+
inputPath: invocation.inputPath,
|
|
907
|
+
repoUrl: invocation.redactedRepoUrl,
|
|
908
|
+
repoUrlSource: invocation.repoUrlSource,
|
|
909
|
+
envPath: invocation.envPath,
|
|
910
|
+
next: {
|
|
911
|
+
apply: 'aops-cli host database dump restore --input <backup.dump> --apply --confirm',
|
|
912
|
+
},
|
|
913
|
+
};
|
|
914
|
+
if (!options.json)
|
|
915
|
+
logSuccess('PG-native dump restore preview ready.');
|
|
916
|
+
printHostDatabaseResult(payload, options);
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
if (interactive) {
|
|
920
|
+
banner('AOPS Host Database Dump Restore');
|
|
921
|
+
logInfo(`Repo: ${invocation.redactedRepoUrl}`);
|
|
922
|
+
logInfo(`Input: ${invocation.inputPath}`);
|
|
923
|
+
logInfo(`Tool: ${invocation.tool}`);
|
|
924
|
+
}
|
|
925
|
+
try {
|
|
926
|
+
const result = await nativePgCommandRuntime.runProcess(invocation.tool, invocation.args);
|
|
927
|
+
if (result.exitCode !== 0) {
|
|
928
|
+
throw new Error(`${path.basename(invocation.tool)} exited with code ${String(result.exitCode ?? 'null')}.`);
|
|
929
|
+
}
|
|
930
|
+
const payload = {
|
|
931
|
+
ok: true,
|
|
932
|
+
action: 'host.database.dump.restore',
|
|
933
|
+
destructive: true,
|
|
934
|
+
tool: invocation.tool,
|
|
935
|
+
args: invocation.redactedArgs,
|
|
936
|
+
inputPath: invocation.inputPath,
|
|
937
|
+
repoUrl: invocation.redactedRepoUrl,
|
|
938
|
+
repoUrlSource: invocation.repoUrlSource,
|
|
939
|
+
envPath: invocation.envPath,
|
|
940
|
+
};
|
|
941
|
+
if (!options.json)
|
|
942
|
+
logSuccess('PG-native dump restore completed.');
|
|
943
|
+
printHostDatabaseResult(payload, options);
|
|
944
|
+
}
|
|
945
|
+
catch (error) {
|
|
946
|
+
logError(`PG-native dump restore failed: ${formatNativePgRunnerError(error, invocation.tool)}`);
|
|
947
|
+
process.exitCode = 1;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
export async function runHostHello(options = {}) {
|
|
951
|
+
const apiState = await createCliApiClientFromOptions(options);
|
|
952
|
+
try {
|
|
953
|
+
const payload = await apiState.client.fetchJson('/api/hello', {
|
|
954
|
+
method: 'GET',
|
|
955
|
+
auth: false,
|
|
956
|
+
retry401: false,
|
|
957
|
+
timeoutMs: options.timeoutMs,
|
|
958
|
+
});
|
|
959
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
960
|
+
}
|
|
961
|
+
catch (error) {
|
|
962
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
963
|
+
logError(`Hello endpoint failed: ${message}`);
|
|
964
|
+
process.exitCode = 1;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
export function makeHostCommand() {
|
|
968
|
+
const cmd = new Command('host').description('Host inventory, registration, diagnostics, and admin commands');
|
|
969
|
+
const configCmd = cmd.command('config').description('Inspect or update the local host-owned env config');
|
|
970
|
+
const databaseCmd = cmd
|
|
971
|
+
.command('database')
|
|
972
|
+
.alias('db')
|
|
973
|
+
.description('Inspect or mutate the active host database via AOPS db-admin routes');
|
|
974
|
+
const backupCmd = databaseCmd
|
|
975
|
+
.command('backup')
|
|
976
|
+
.description('Export or restore hosted database backups');
|
|
977
|
+
const dumpCmd = databaseCmd
|
|
978
|
+
.command('dump')
|
|
979
|
+
.description('Run PG-native pg_dump / pg_restore against the configured PostgreSQL repo URL');
|
|
980
|
+
applyCommonOptions(configCmd
|
|
981
|
+
.command('show')
|
|
982
|
+
.description('Show repo target and host log level from the local host env file')
|
|
983
|
+
.option('--env-path <path>', 'Explicit host env file path (default: ~/.aops/aops.server.env)')
|
|
984
|
+
.action(async (options) => {
|
|
985
|
+
await runHostConfigShow(options);
|
|
986
|
+
}), { withAuth: false, withProject: false });
|
|
987
|
+
applyCommonOptions(configCmd
|
|
988
|
+
.command('set')
|
|
989
|
+
.description('Write repo target and/or host log level into the local host env file')
|
|
990
|
+
.option('--env-path <path>', 'Explicit host env file path (default: ~/.aops/aops.server.env)')
|
|
991
|
+
.option('--repo-url-env <name>', 'Read the shared host repository URL from this environment variable')
|
|
992
|
+
.option('--log-level <level>', `Host log level (${HOST_LOG_LEVELS.join(', ')})`)
|
|
993
|
+
.action(async (options) => {
|
|
994
|
+
await runHostConfigSet(options);
|
|
995
|
+
}), { withAuth: false, withProject: false });
|
|
996
|
+
applyHostRegistrationOptions(applyCommonOptions(cmd
|
|
997
|
+
.command('register')
|
|
998
|
+
.description('Install a JSON host registration manifest into the operator registry')
|
|
999
|
+
.requiredOption('--from <path>', 'Path to a host registration JSON document')
|
|
1000
|
+
.action(async (options) => {
|
|
1001
|
+
await runHostRegister(options);
|
|
1002
|
+
}), { withAuth: false, withProject: false }));
|
|
1003
|
+
applyHostRegistrationOptions(applyCommonOptions(cmd.command('registrations').description('List installed host registrations in the operator registry').action(async (options) => {
|
|
1004
|
+
await runHostRegistrations(options);
|
|
1005
|
+
}), { withAuth: false, withProject: false }));
|
|
1006
|
+
applyHostRegistrationOptions(applyCommonOptions(cmd
|
|
1007
|
+
.command('unregister')
|
|
1008
|
+
.description('Remove an installed host registration')
|
|
1009
|
+
.requiredOption('--domain <domain>', 'Domain id')
|
|
1010
|
+
.action(async (options) => {
|
|
1011
|
+
await runHostUnregister(options);
|
|
1012
|
+
}), { withAuth: false, withProject: false }));
|
|
1013
|
+
applyHostRegistrationOptions(applyCommonOptions(cmd
|
|
1014
|
+
.command('explain-registration')
|
|
1015
|
+
.description('Explain the stored registration manifest and projected host-config fragment')
|
|
1016
|
+
.requiredOption('--domain <domain>', 'Domain id')
|
|
1017
|
+
.action(async (options) => {
|
|
1018
|
+
await runHostExplainRegistration(options);
|
|
1019
|
+
}), { withAuth: false, withProject: false }));
|
|
1020
|
+
applyCommonOptions(cmd.command('health').description('Smoke the runtime health endpoint (GET /api/health)').action(async (options) => {
|
|
1021
|
+
await runHostHealth(options);
|
|
1022
|
+
}), { withAuth: false, withProject: false });
|
|
1023
|
+
applyCommonOptions(cmd
|
|
1024
|
+
.command('diagnostics')
|
|
1025
|
+
.alias('plugins')
|
|
1026
|
+
.description('Inspect host runtime diagnostics (/api/host-admin/plugins)')
|
|
1027
|
+
.option('--reset', 'Reset plugin registry and agent gateway catalog snapshot before diagnostics')
|
|
1028
|
+
.option('--warmup', 'Warmup plugin registry before diagnostics')
|
|
1029
|
+
.action(async (options) => {
|
|
1030
|
+
await runHostDiagnostics(options);
|
|
1031
|
+
}), { withProject: false });
|
|
1032
|
+
applyCommonOptions(databaseCmd
|
|
1033
|
+
.command('status')
|
|
1034
|
+
.description('Load hosted database status (/api/aops/settings/database/status)')
|
|
1035
|
+
.action(async (options) => {
|
|
1036
|
+
await runHostDatabaseStatus(options);
|
|
1037
|
+
}), { withProject: false, withYes: false });
|
|
1038
|
+
applyCommonOptions(databaseCmd
|
|
1039
|
+
.command('reset')
|
|
1040
|
+
.description('Reset hosted database tables and optionally recreate schema')
|
|
1041
|
+
.option('--mode <mode>', 'Reset mode (drop-only or drop-and-recreate)')
|
|
1042
|
+
.option('--include-auth-tables', 'Also reset auth tables')
|
|
1043
|
+
.option('--preview', 'Show the reset payload without calling the server')
|
|
1044
|
+
.option('--apply', 'Execute the hosted database reset')
|
|
1045
|
+
.option('--confirm', 'Required with --apply because this command deletes hosted state')
|
|
1046
|
+
.option('--confirm-text <text>', 'Override the destructive confirmation text sent to the server')
|
|
1047
|
+
.action(async (options) => {
|
|
1048
|
+
await runHostDatabaseReset(options);
|
|
1049
|
+
}), { withProject: false, withYes: false });
|
|
1050
|
+
applyCommonOptions(backupCmd
|
|
1051
|
+
.command('export')
|
|
1052
|
+
.description('Export a hosted database backup through the AOPS backup route')
|
|
1053
|
+
.option('--include-auth-tables', 'Also export auth tables')
|
|
1054
|
+
.option('--table <name>', 'Limit export to a configured table', collectRepeatedOption, [])
|
|
1055
|
+
.option('--output <path>', 'Write backup JSON to a file instead of stdout')
|
|
1056
|
+
.action(async (options) => {
|
|
1057
|
+
await runHostDatabaseBackupExport(options);
|
|
1058
|
+
}), { withProject: false, withYes: false });
|
|
1059
|
+
applyCommonOptions(backupCmd
|
|
1060
|
+
.command('restore')
|
|
1061
|
+
.description('Restore a hosted database backup through the AOPS restore route')
|
|
1062
|
+
.option('--input <path>', 'Read backup JSON from a file')
|
|
1063
|
+
.option('--input-json <json>', 'Inline backup JSON or @file.json')
|
|
1064
|
+
.option('--mode <mode>', 'Restore mode (truncate-and-insert or insert-only)')
|
|
1065
|
+
.option('--preview', 'Show the restore payload without calling the server')
|
|
1066
|
+
.option('--apply', 'Execute the hosted backup restore')
|
|
1067
|
+
.option('--confirm', 'Required with --apply because this command mutates hosted state')
|
|
1068
|
+
.option('--confirm-text <text>', 'Override the destructive confirmation text sent to the server')
|
|
1069
|
+
.action(async (options) => {
|
|
1070
|
+
await runHostDatabaseBackupRestore(options);
|
|
1071
|
+
}), { withProject: false, withYes: false });
|
|
1072
|
+
applyCommonOptions(dumpCmd
|
|
1073
|
+
.command('export')
|
|
1074
|
+
.description('Write a native PostgreSQL custom dump file with pg_dump')
|
|
1075
|
+
.option('--env-path <path>', 'Path to host env file used to resolve repo URL')
|
|
1076
|
+
.option('--pg-bin-dir <path>', 'Directory containing pg_dump / pg_restore executables')
|
|
1077
|
+
.requiredOption('--output <path>', 'Write dump output to this file path')
|
|
1078
|
+
.option('--table <name>', 'Limit dump to a table', collectRepeatedOption, [])
|
|
1079
|
+
.option('--schema-only', 'Dump schema only')
|
|
1080
|
+
.option('--data-only', 'Dump data only')
|
|
1081
|
+
.action(async (options) => {
|
|
1082
|
+
await runHostDatabaseDumpExport(options);
|
|
1083
|
+
}), { withProject: false, withYes: false });
|
|
1084
|
+
applyCommonOptions(dumpCmd
|
|
1085
|
+
.command('restore')
|
|
1086
|
+
.description('Restore a native PostgreSQL custom dump file with pg_restore')
|
|
1087
|
+
.option('--env-path <path>', 'Path to host env file used to resolve repo URL')
|
|
1088
|
+
.option('--pg-bin-dir <path>', 'Directory containing pg_dump / pg_restore executables')
|
|
1089
|
+
.requiredOption('--input <path>', 'Path to a native PostgreSQL dump file')
|
|
1090
|
+
.option('--table <name>', 'Restore only a table from the dump', collectRepeatedOption, [])
|
|
1091
|
+
.option('--schema-only', 'Restore schema only')
|
|
1092
|
+
.option('--data-only', 'Restore data only')
|
|
1093
|
+
.option('--clean', 'Drop database objects before recreating them')
|
|
1094
|
+
.option('--preview', 'Show the pg_restore invocation without executing it')
|
|
1095
|
+
.option('--apply', 'Execute pg_restore')
|
|
1096
|
+
.option('--confirm', 'Required with --apply because this command mutates database state')
|
|
1097
|
+
.action(async (options) => {
|
|
1098
|
+
await runHostDatabaseDumpRestore(options);
|
|
1099
|
+
}), { withProject: false, withYes: false });
|
|
1100
|
+
applyCommonOptions(cmd.command('hello').description('Smoke the hello endpoint (GET /api/hello)').action(async (options) => {
|
|
1101
|
+
await runHostHello(options);
|
|
1102
|
+
}), { withAuth: false, withProject: false });
|
|
1103
|
+
cmd.addHelpText('after', `
|
|
1104
|
+
Examples:
|
|
1105
|
+
aops-cli host config show
|
|
1106
|
+
aops-cli setup server-env
|
|
1107
|
+
aops-cli host config set --log-level info
|
|
1108
|
+
aops-cli host config set --repo-url-env AOPS_REPO_URL
|
|
1109
|
+
aops-cli host database status
|
|
1110
|
+
aops-cli host database reset --mode drop-and-recreate --preview
|
|
1111
|
+
aops-cli host database reset --mode drop-and-recreate --include-auth-tables --apply --confirm
|
|
1112
|
+
aops-cli host database backup export --table prompts --table prompt-versions --output ./aops-backup.json
|
|
1113
|
+
aops-cli host database backup restore --input ./aops-backup.json --mode truncate-and-insert --apply --confirm
|
|
1114
|
+
aops-cli host database dump export --output ./aops.dump
|
|
1115
|
+
aops-cli host database dump restore --input ./aops.dump --preview
|
|
1116
|
+
aops-cli host database dump restore --input ./aops.dump --clean --apply --confirm
|
|
1117
|
+
aops-cli host register --from /path/to/host-registration.json
|
|
1118
|
+
aops-cli host registrations
|
|
1119
|
+
aops-cli host explain-registration --domain fileman
|
|
1120
|
+
aops-cli host unregister --domain fileman
|
|
1121
|
+
aops-cli host health
|
|
1122
|
+
aops-cli host diagnostics --warmup
|
|
1123
|
+
aops-cli host diagnostics --reset --warmup
|
|
1124
|
+
aops-cli host hello
|
|
1125
|
+
`);
|
|
1126
|
+
return cmd;
|
|
1127
|
+
}
|