@aopslabs/aops 0.2.1 → 0.3.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.
@@ -1,14 +1,12 @@
1
1
  import path from 'node:path';
2
- import { banner, logInfo, logSuccess, logWarn, withSpinner } from '@aopslabs/xf-cli-ui';
2
+ import { logInfo, logSuccess, logWarn } from '@aopslabs/xf-cli-ui';
3
3
  import { canonicalCommercialJson, managedInstallationLayoutBinding, sha256Commercial, } from '@aopslabs/artifact-trust-contracts';
4
- import { runAuthLogin } from '../commands/auth/login.js';
5
4
  import { runCommunityServerSetup } from '../commands/community-server.js';
6
5
  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';
6
+ import { inspectSetupReadiness, parseSetupPath, } from './setup-readiness.js';
7
+ import { applySetupAgentAssets, } from './setup-agent-assets-bridge.js';
10
8
  import { defaultLocalPostgresAdminUser, defaultLocalPostgresDatabase, provisionLocalPostgres, } from './setup-local-postgres.js';
11
- import { isExternalPostgresTlsProbeError, probeExternalPostgresConnection, } from './setup-external-postgres.js';
9
+ import { probeExternalPostgresConnection } from './setup-external-postgres.js';
12
10
  import { assertCommunityNativeApplicationCurrent, inspectCommunityNativeInstall, inspectCommunityNativeSource, planCommunityNativeInstalledMigration, resolveCommunityNativeDefaultSourceRoot, stopCommunityNativeInstall, } from './community-native-lifecycle.js';
13
11
  import { startCommunityNativeCockpit, stopCommunityNativeCockpit, } from './community-cockpit-lifecycle.js';
14
12
  import { CommunityDiagnosticError, isCommunityDiagnosticV1, } from './community-diagnostic.js';
@@ -144,22 +142,6 @@ function resolveSetupLocalSecurity(selectedPath, requestedAuth, requestedExposur
144
142
  }
145
143
  return Object.freeze({ authProvider, exposure, explicit });
146
144
  }
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
145
  function validateLocalPostgresAdminPassword(value) {
164
146
  if (value.length > 1_024)
165
147
  return 'Use no more than 1024 characters.';
@@ -167,22 +149,6 @@ function validateLocalPostgresAdminPassword(value) {
167
149
  return 'The password cannot contain line breaks or NUL characters.';
168
150
  return true;
169
151
  }
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
152
  function printSetupReadiness(result) {
187
153
  for (const check of result.checks) {
188
154
  const prefix = check.state === 'ready'
@@ -237,79 +203,17 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
237
203
  const startInstalledCockpit = dependencies.startInstalledCockpit ?? startCommunityNativeCockpit;
238
204
  const stopInstalledCockpit = dependencies.stopInstalledCockpit ?? stopCommunityNativeCockpit;
239
205
  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
206
  const directProgress = async (_label, action) => action();
247
- const progress = interactive
248
- ? dependencies.progress ?? (process.stdout.isTTY === true ? withSpinner : directProgress)
249
- : directProgress;
207
+ const progress = directProgress;
250
208
  const requestedAgentAssetsAction = normalizeAgentAssetsAction(options.agentAssets);
251
209
  const requestedPath = normalizeNonEmpty(options.path);
252
210
  if (requestedPath && !parseSetupPath(requestedPath)) {
253
211
  throw new Error('setup_init_path_invalid:choose_1_2_3_or_4');
254
212
  }
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
- }
213
+ const selectedPath = parseSetupPath(requestedPath);
286
214
  const localSecurity = resolveSetupLocalSecurity(selectedPath, options.auth, options.exposure);
287
215
  let effectiveApiBaseUrl = normalizeNonEmpty(options.apiBaseUrl);
288
216
  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
217
  let postgresTls = options.postgresTls;
314
218
  if (selectedPath === 'native-external' && !postgresTls)
315
219
  postgresTls = 'require';
@@ -321,39 +225,6 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
321
225
  ?? defaultLocalPostgresDatabase(options.instance);
322
226
  let localPostgresAppUser = normalizeNonEmpty(options.localPostgresAppUser)
323
227
  ?? 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
228
  if (selectedPath && !['native-external', 'native-local'].includes(selectedPath) && options.postgresConfig) {
358
229
  throw new Error('setup_init_postgres_config_only_valid_for_paths_1_or_3');
359
230
  }
@@ -393,26 +264,14 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
393
264
  agentAssetsProvider: dependencies.agentAssets,
394
265
  timeoutMs: options.timeoutMs,
395
266
  });
396
- let initial = await inspect();
267
+ const initial = await inspect();
397
268
  const initialServerEnv = initial.checks.find((check) => check.id === 'global-server-env');
398
269
  if (!localSecurity.explicit &&
399
270
  (initialServerEnv?.data?.authProvider === 'trusted-local')) {
400
271
  effectiveAuthProvider = initialServerEnv.data.authProvider;
401
272
  effectiveExposure = canonicalSetupExposure(effectiveAuthProvider);
402
273
  }
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));
274
+ const shouldApply = options.apply === true;
416
275
  const installerPlan = createSetupInstallerPlan(options, selectedPath, localSecurity, initial, {
417
276
  postgresConfig: effectivePostgresConfig,
418
277
  postgresTls: effectivePostgresTls,
@@ -433,10 +292,7 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
433
292
  }, null, 2));
434
293
  return initial;
435
294
  }
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.');
295
+ printSetupReadiness(initial);
440
296
  return initial;
441
297
  }
442
298
  if (!selectedPath)
@@ -464,31 +320,8 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
464
320
  if (selectedPath === 'native-external' && !postgresTls) {
465
321
  throw new Error('setup_init_postgres_tls_required_for_path_1');
466
322
  }
467
- let createPostgresSecret;
323
+ const createPostgresSecret = undefined;
468
324
  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
325
  const localServerPath = selectedPath !== 'cli-existing';
493
326
  const localApiBaseUrl = effectiveApiBaseUrl ?? `http://127.0.0.1:${options.port ?? 5900}`;
494
327
  let officialCatalogRelease;
@@ -523,36 +356,7 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
523
356
  if (selectedPath === 'native-external') {
524
357
  const envCheck = initial.checks.find((check) => check.id === 'global-server-env');
525
358
  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 &&
359
+ if (!envReady &&
556
360
  localSecurity.explicit &&
557
361
  envCheck?.data?.postgresReady === true) {
558
362
  if (!dependencies.setupServerEnv) {
@@ -601,35 +405,9 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
601
405
  connection = await testConnection();
602
406
  }
603
407
  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();
408
+ throw error;
628
409
  }
629
410
  steps.push({ action: 'setup.postgres-connection', ...connection });
630
- if (interactive) {
631
- logSuccess(`PostgreSQL connection verified (${connection.transport}, server ${connection.serverMajor}).`);
632
- }
633
411
  }
634
412
  if (selectedPath === 'native-local') {
635
413
  const localCheck = initial.checks.find((check) => check.id === 'local-postgresql');
@@ -694,13 +472,7 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
694
472
  const passwordValidation = validateLocalPostgresAdminPassword(adminPassword);
695
473
  if (passwordValidation !== true)
696
474
  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) {
475
+ if (!adminPassword && options.localPostgresAdminNoPassword !== true) {
704
476
  throw new Error('setup_init_local_postgres_admin_password_required:use_private_environment_or_--local-postgres-admin-no-password');
705
477
  }
706
478
  const provision = dependencies.provisionLocalPostgres ?? provisionLocalPostgres;
@@ -786,8 +558,6 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
786
558
  migrationAction: 'verify-only',
787
559
  acceptedPlanSha256: installedPlan.planning.acceptedPlanSha256,
788
560
  });
789
- if (interactive)
790
- logSuccess('Running AOPS server database schema is already current.');
791
561
  }
792
562
  }
793
563
  catch (error) {
@@ -814,7 +584,6 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
814
584
  }
815
585
  if (!reuseRunningServer) {
816
586
  let lifecycleResult;
817
- const reportedStages = new Set();
818
587
  await progress('Preparing PostgreSQL, verifying migrations, and starting AOPS server...', () => setupCommunityServer({
819
588
  runtime: 'native',
820
589
  postgres: selectedPath === 'native-external' || selectedPath === 'native-local'
@@ -838,19 +607,10 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
838
607
  createPostgresSecret: selectedPath === 'native-container' ? createPostgresSecret : undefined,
839
608
  apply: true,
840
609
  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,
610
+ progressSink: undefined,
849
611
  resultSink: (result) => { lifecycleResult = result; },
850
612
  }));
851
613
  steps.push({ action: 'community-server.setup', status: 'applied', result: lifecycleResult ?? null });
852
- if (interactive)
853
- printMigrationVerification(lifecycleResult);
854
614
  }
855
615
  const cockpit = await progress('Starting AOPS Cockpit on its separate loopback port...', () => startInstalledCockpit({
856
616
  instanceName: options.instance,
@@ -926,12 +686,6 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
926
686
  }
927
687
  else if (!agentAssetsAction && dependencies.agentAssets?.apply) {
928
688
  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
689
  agentAssetsAction = recommendedAction;
936
690
  }
937
691
  if (agentAssetsAction === 'install' || agentAssetsAction === 'repair') {
@@ -956,13 +710,6 @@ export async function runSetupInitOrchestrator(options = {}, dependencies = {})
956
710
  steps.push({ action: `assets.${agentAssetsAction}`, status: appliedAssets.state, target: 'all' });
957
711
  result = await inspect();
958
712
  }
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
713
  if (options.json) {
967
714
  console.log(JSON.stringify({
968
715
  command: 'setup.init',
@@ -46,7 +46,7 @@ export function buildAopsInstallAgentPrompt() {
46
46
  1. Run \`aops setup guide --json\` and follow its packaged \`aops-install\` skill as the current installation guide.
47
47
  2. Run \`aops setup init --yes --json\` first and explain the available PostgreSQL paths and remaining actions briefly.
48
48
  3. Ask me only for choices or authority you cannot safely infer. Use the installed command's exact nested \`--help\`; do not guess flags.
49
- 4. Never ask me to paste PostgreSQL URLs or passwords into chat and never place secrets in command arguments. Let me enter private values through AOPS's masked interactive prompts.
49
+ 4. Never ask me to paste PostgreSQL URLs or passwords into chat and never place secrets in command arguments. Pass private values through the documented environment variables or private configuration files.
50
50
  5. Keep the signed official catalog and Gateway assets for all registered agent runtimes unless I explicitly opt out. Do not seed starter/demo user data.
51
51
  6. Apply the selected setup path, then verify migrations, server health, Gateway asset bindings, and Cockpit. Report the Cockpit URL and any remaining safe action.`;
52
52
  }
package/dist/main.js CHANGED
@@ -36,7 +36,6 @@ import { makePmCommand } from './commands/pm/index.js';
36
36
  import { makeCommunityServerCommand } from './commands/community-server.js';
37
37
  import { makeCommunityCockpitCommand } from './commands/community-cockpit.js';
38
38
  import { makeCommunityDoctorCommand } from './commands/community-doctor.js';
39
- import { makeCommunityConsoleCommand } from './commands/community-console.js';
40
39
  import { makeTargetCommand } from './commands/target.js';
41
40
  import { makeVersionCommand } from './commands/version.js';
42
41
  import { launchBundledTui, shouldLaunchBundledTui } from './lib/tui-launcher.js';
@@ -92,7 +91,6 @@ export function buildCommunityProgram() {
92
91
  program.addCommand(makeCommunityServerCommand());
93
92
  program.addCommand(makeCommunityCockpitCommand());
94
93
  program.addCommand(makeCommunityDoctorCommand());
95
- program.addCommand(makeCommunityConsoleCommand());
96
94
  program.addCommand(makeTargetCommand());
97
95
  program.addCommand(makeVersionCommand());
98
96
  program.addHelpText('after', `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aopslabs/aops",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "AOPS CLI and terminal setup application.",
6
6
  "aopsDockerServerVersion": "0.2.2",
@@ -48,9 +48,8 @@
48
48
  "test:r6-auth-cutover": "node --test test/r6-auth-cutover.test.mjs",
49
49
  "test:container-runtime": "node --test test/container-runtime.test.mjs",
50
50
  "test:home": "node --test test/home-menu.test.mjs",
51
- "test:console": "node --test test/community-console.test.mjs",
52
51
  "test:launchers": "node --test test/terminal-launchers.test.mjs",
53
- "test:shortcuts": "pnpm run test:home && pnpm run test:cockpit && pnpm run test:console && pnpm run test:launchers && pnpm run test:assets-menu && pnpm run test:agent-assets-content && pnpm run test:setup-install && pnpm run test:container-runtime && pnpm run test:native-lifecycle && pnpm run test:operation-journal && pnpm run test:commercial-canonical-order && pnpm run test:commercial-runtime-closure && pnpm run test:commercial-artifact && pnpm run test:commercial-final-readiness && pnpm run test:commercial-admission && pnpm run test:commercial-license && pnpm run test:commercial-runbook && pnpm run test:package-identity && pnpm run test:skill-discovery && pnpm run test:target-transport && pnpm run test:target-auth && pnpm run test:r6-auth-cutover && pnpm run test:r6-cutover-baseline",
52
+ "test:shortcuts": "pnpm run test:home && pnpm run test:cockpit && pnpm run test:launchers && pnpm run test:assets-menu && pnpm run test:agent-assets-content && pnpm run test:setup-install && pnpm run test:container-runtime && pnpm run test:native-lifecycle && pnpm run test:operation-journal && pnpm run test:commercial-canonical-order && pnpm run test:commercial-runtime-closure && pnpm run test:commercial-artifact && pnpm run test:commercial-final-readiness && pnpm run test:commercial-admission && pnpm run test:commercial-license && pnpm run test:commercial-runbook && pnpm run test:package-identity && pnpm run test:skill-discovery && pnpm run test:target-transport && pnpm run test:target-auth && pnpm run test:r6-auth-cutover && pnpm run test:r6-cutover-baseline",
54
53
  "typecheck": "tsc -p tsconfig.json --noEmit",
55
54
  "start": "node dist/main.js"
56
55
  },
@@ -67,7 +66,6 @@
67
66
  "@aopslabs/domain-product-client-chatv3": "0.2.0",
68
67
  "@aopslabs/xf-cli-ui": "0.2.0",
69
68
  "commander": "14.0.3",
70
- "inquirer": "13.3.0",
71
69
  "pg": "8.20.0",
72
70
  "sigstore": "4.1.1"
73
71
  },
@@ -1,109 +0,0 @@
1
- import { Command } from 'commander';
2
- import { logInfo } from '@aopslabs/xf-cli-ui';
3
- import { promptSelect } from '../utils/prompts.js';
4
- import { runCommercialLicenseStatus } from './commercial-license.js';
5
- import { runCommunityDoctor } from './community-doctor.js';
6
- import { runCommunityCockpit, runCommunityCockpitHealth, runCommunityCockpitLogs, runCommunityCockpitRestart, runCommunityCockpitStart, runCommunityCockpitStatus, runCommunityCockpitStop, } from './community-cockpit.js';
7
- import { runCommunityServerHealth, runCommunityServerLogs, runCommunityServerRestart, runCommunityServerStart, runCommunityServerStatus, runCommunityServerStop, } from './community-server.js';
8
- export const COMMUNITY_CONSOLE_CHOICES = Object.freeze([
9
- { name: 'Open Cockpit — starts stopped services if needed', value: 'cockpit' },
10
- { name: 'Show both service statuses', value: 'status' },
11
- { name: 'Start AOPS Server — 5900', value: 'server-start' },
12
- { name: 'Start AOPS Server in this terminal — live logs, Ctrl+C to stop', value: 'server-start-foreground' },
13
- { name: 'Stop AOPS Server — 5900', value: 'server-stop' },
14
- { name: 'Restart AOPS Server — 5900', value: 'server-restart' },
15
- { name: 'Check AOPS Server health', value: 'server-health' },
16
- { name: 'Show AOPS Server logs', value: 'server-logs' },
17
- { name: 'Start Cockpit — 5922', value: 'cockpit-start' },
18
- { name: 'Stop Cockpit — 5922', value: 'cockpit-stop' },
19
- { name: 'Restart Cockpit — 5922', value: 'cockpit-restart' },
20
- { name: 'Check Cockpit health', value: 'cockpit-health' },
21
- { name: 'Show Cockpit logs', value: 'cockpit-logs' },
22
- { name: 'Show commercial license and domain-admission status', value: 'license-status' },
23
- { name: 'Run Doctor (read-only)', value: 'doctor' },
24
- { name: 'Back', value: 'back' },
25
- ]);
26
- export async function runCommunityConsoleAction(action, options, dependencies = {}) {
27
- if (action === 'cockpit')
28
- return (dependencies.runCockpit ?? runCommunityCockpit)(options);
29
- if (action === 'status') {
30
- await (dependencies.runServerStatus ?? runCommunityServerStatus)(options);
31
- await (dependencies.runCockpitStatus ?? runCommunityCockpitStatus)(options);
32
- return;
33
- }
34
- if (action === 'server-health')
35
- return (dependencies.runServerHealth ?? runCommunityServerHealth)(options);
36
- if (action === 'server-start')
37
- return (dependencies.runServerStart ?? runCommunityServerStart)(options);
38
- if (action === 'server-start-foreground')
39
- return (dependencies.runServerStart ?? runCommunityServerStart)({
40
- ...options,
41
- foreground: true,
42
- });
43
- if (action === 'server-restart')
44
- return (dependencies.runServerRestart ?? runCommunityServerRestart)(options);
45
- if (action === 'server-stop')
46
- return (dependencies.runServerStop ?? runCommunityServerStop)(options);
47
- if (action === 'server-logs')
48
- return (dependencies.runServerLogs ?? runCommunityServerLogs)(options);
49
- if (action === 'cockpit-health')
50
- return (dependencies.runCockpitHealth ?? runCommunityCockpitHealth)(options);
51
- if (action === 'cockpit-start')
52
- return (dependencies.runCockpitStart ?? runCommunityCockpitStart)(options);
53
- if (action === 'cockpit-restart')
54
- return (dependencies.runCockpitRestart ?? runCommunityCockpitRestart)(options);
55
- if (action === 'cockpit-stop')
56
- return (dependencies.runCockpitStop ?? runCommunityCockpitStop)(options);
57
- if (action === 'cockpit-logs')
58
- return (dependencies.runCockpitLogs ?? runCommunityCockpitLogs)(options);
59
- if (action === 'license-status') {
60
- return (dependencies.runLicenseStatus ?? runCommercialLicenseStatus)({ json: options.json });
61
- }
62
- return (dependencies.runDoctor ?? runCommunityDoctor)(options);
63
- }
64
- export async function runCommunityConsole(options = {}, dependencies = {}) {
65
- const interactive = dependencies.isInteractive?.() ??
66
- (process.stdin.isTTY === true && process.stdout.isTTY === true);
67
- if (!interactive || options.json === true) {
68
- console.log(JSON.stringify({
69
- status: 'needs-input',
70
- mutationPerformed: false,
71
- reason: 'community_console_tty_required',
72
- next: [
73
- 'aops server status --json',
74
- 'aops server start --json',
75
- 'aops server stop --json',
76
- 'aops cockpit status --json',
77
- 'aops cockpit start --json',
78
- 'aops cockpit stop --json',
79
- 'aops license status --json',
80
- ],
81
- }, null, 2));
82
- process.exitCode = 2;
83
- return;
84
- }
85
- const select = dependencies.select ?? promptSelect;
86
- const info = dependencies.info ?? logInfo;
87
- info('AOPS Server and Cockpit use separate processes and ports: 5900 and 5922.');
88
- await (dependencies.runServerStatus ?? runCommunityServerStatus)(options);
89
- await (dependencies.runCockpitStatus ?? runCommunityCockpitStatus)(options);
90
- while (true) {
91
- const action = await select({
92
- message: 'Server and Cockpit:',
93
- type: process.env.AOPS_CLI_MENU_STYLE?.toLowerCase() === 'rawlist' ? 'rawlist' : 'select',
94
- pageSize: COMMUNITY_CONSOLE_CHOICES.length,
95
- choices: [...COMMUNITY_CONSOLE_CHOICES],
96
- });
97
- if (action === 'back')
98
- return;
99
- await runCommunityConsoleAction(action, options, dependencies);
100
- }
101
- }
102
- export function makeCommunityConsoleCommand() {
103
- return new Command('console')
104
- .description('Guided server and Cockpit controls; non-TTY returns needs-input without mutation')
105
- .option('--instance <name>', 'Installation instance name', 'default')
106
- .option('--data-root <path>', 'Absolute Community data root override')
107
- .option('--json', 'Return the non-interactive needs-input contract')
108
- .action((options) => runCommunityConsole(options));
109
- }
@@ -1,70 +0,0 @@
1
- import inquirer from 'inquirer';
2
- const DONE_PREFIX = '\u2714 ';
3
- const PROMPT_THEME = { prefix: { idle: '?', done: DONE_PREFIX } };
4
- const normalizePromptMessage = (message) => message.trimStart();
5
- export async function promptInput(opts) {
6
- const { value } = await inquirer.prompt([
7
- {
8
- type: 'input',
9
- name: 'value',
10
- message: normalizePromptMessage(opts.message),
11
- default: opts.default,
12
- validate: opts.validate,
13
- theme: PROMPT_THEME,
14
- },
15
- ]);
16
- return String(value ?? '');
17
- }
18
- export async function promptPassword(opts) {
19
- const { value } = await inquirer.prompt([
20
- {
21
- type: 'password',
22
- name: 'value',
23
- message: normalizePromptMessage(opts.message),
24
- default: opts.default,
25
- mask: '*',
26
- validate: opts.validate,
27
- theme: PROMPT_THEME,
28
- },
29
- ]);
30
- return String(value ?? '');
31
- }
32
- export async function promptConfirm(opts) {
33
- const { confirm } = await inquirer.prompt([
34
- {
35
- type: 'confirm',
36
- name: 'confirm',
37
- message: normalizePromptMessage(opts.message),
38
- default: opts.default ?? true,
39
- theme: PROMPT_THEME,
40
- },
41
- ]);
42
- return Boolean(confirm);
43
- }
44
- export async function promptSelect(opts) {
45
- const resolvedType = opts.type === 'list' || !opts.type ? 'select' : opts.type;
46
- const { value } = await inquirer.prompt([
47
- {
48
- type: resolvedType,
49
- name: 'value',
50
- message: normalizePromptMessage(opts.message),
51
- choices: opts.choices,
52
- default: opts.default,
53
- pageSize: opts.pageSize,
54
- theme: PROMPT_THEME,
55
- },
56
- ]);
57
- return String(value);
58
- }
59
- export async function promptMultiSelect(opts) {
60
- const { values } = await inquirer.prompt([
61
- {
62
- type: 'checkbox',
63
- name: 'values',
64
- message: normalizePromptMessage(opts.message),
65
- choices: opts.choices,
66
- theme: PROMPT_THEME,
67
- },
68
- ]);
69
- return Array.isArray(values) ? values.map((v) => String(v)) : [];
70
- }