fluxmail 0.9.0 → 0.11.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/README.md +1 -1
- package/dist/accounts/googleAuth.d.ts +4 -2
- package/dist/accounts/googleAuth.d.ts.map +1 -1
- package/dist/accounts/googleAuth.js +20 -85
- package/dist/accounts/googleAuth.js.map +1 -1
- package/dist/accounts/microsoftAuth.d.ts +2 -1
- package/dist/accounts/microsoftAuth.d.ts.map +1 -1
- package/dist/accounts/microsoftAuth.js +16 -80
- package/dist/accounts/microsoftAuth.js.map +1 -1
- package/dist/accounts/oauthCallback.d.ts +52 -0
- package/dist/accounts/oauthCallback.d.ts.map +1 -0
- package/dist/accounts/oauthCallback.js +237 -0
- package/dist/accounts/oauthCallback.js.map +1 -0
- package/dist/accounts/registry.d.ts.map +1 -1
- package/dist/accounts/registry.js +12 -5
- package/dist/accounts/registry.js.map +1 -1
- package/dist/accounts/telemetry.d.ts +6 -0
- package/dist/accounts/telemetry.d.ts.map +1 -1
- package/dist/accounts/telemetry.js +19 -0
- package/dist/accounts/telemetry.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +114 -36
- package/dist/cli.js.map +1 -1
- package/dist/cliInstances.d.ts +5 -2
- package/dist/cliInstances.d.ts.map +1 -1
- package/dist/cliInstances.js +74 -22
- package/dist/cliInstances.js.map +1 -1
- package/dist/cliMail.d.ts +2 -0
- package/dist/cliMail.d.ts.map +1 -1
- package/dist/cliMail.js +113 -19
- package/dist/cliMail.js.map +1 -1
- package/dist/cliOutput.d.ts +9 -0
- package/dist/cliOutput.d.ts.map +1 -0
- package/dist/cliOutput.js +76 -0
- package/dist/cliOutput.js.map +1 -0
- package/dist/context.js +1 -1
- package/dist/context.js.map +1 -1
- package/dist/http/admin.d.ts.map +1 -1
- package/dist/http/admin.js +2 -0
- package/dist/http/admin.js.map +1 -1
- package/dist/http/app.d.ts.map +1 -1
- package/dist/http/app.js +4 -0
- package/dist/http/app.js.map +1 -1
- package/dist/http/identity.d.ts.map +1 -1
- package/dist/http/identity.js +2 -0
- package/dist/http/identity.js.map +1 -1
- package/dist/http/rest.d.ts.map +1 -1
- package/dist/http/rest.js +270 -48
- package/dist/http/rest.js.map +1 -1
- package/dist/licensing/entitlements.d.ts +23 -5
- package/dist/licensing/entitlements.d.ts.map +1 -1
- package/dist/licensing/entitlements.js +101 -22
- package/dist/licensing/entitlements.js.map +1 -1
- package/dist/licensing/lease.d.ts +1 -1
- package/dist/licensing/lease.d.ts.map +1 -1
- package/dist/licensing/refresher.d.ts.map +1 -1
- package/dist/licensing/refresher.js +5 -2
- package/dist/licensing/refresher.js.map +1 -1
- package/dist/mcp/buildServer.d.ts.map +1 -1
- package/dist/mcp/buildServer.js +236 -78
- package/dist/mcp/buildServer.js.map +1 -1
- package/dist/mcp/outputSchemas.d.ts +2923 -0
- package/dist/mcp/outputSchemas.d.ts.map +1 -0
- package/dist/mcp/outputSchemas.js +108 -0
- package/dist/mcp/outputSchemas.js.map +1 -0
- package/dist/scheduler/sendScheduler.d.ts +2 -0
- package/dist/scheduler/sendScheduler.d.ts.map +1 -1
- package/dist/scheduler/sendScheduler.js +13 -3
- package/dist/scheduler/sendScheduler.js.map +1 -1
- package/dist/service/deliveryCoordinator.d.ts +45 -0
- package/dist/service/deliveryCoordinator.d.ts.map +1 -0
- package/dist/service/deliveryCoordinator.js +296 -0
- package/dist/service/deliveryCoordinator.js.map +1 -0
- package/dist/service/emailService.d.ts +48 -5
- package/dist/service/emailService.d.ts.map +1 -1
- package/dist/service/emailService.js +258 -37
- package/dist/service/emailService.js.map +1 -1
- package/dist/service/publicErrors.d.ts +12 -0
- package/dist/service/publicErrors.d.ts.map +1 -0
- package/dist/service/publicErrors.js +41 -0
- package/dist/service/publicErrors.js.map +1 -0
- package/dist/service/searchCursor.d.ts +2 -0
- package/dist/service/searchCursor.d.ts.map +1 -1
- package/dist/service/searchCursor.js +6 -2
- package/dist/service/searchCursor.js.map +1 -1
- package/dist/storage/db.d.ts +252 -2
- package/dist/storage/db.d.ts.map +1 -1
- package/dist/storage/db.js +57 -1
- package/dist/storage/db.js.map +1 -1
- package/dist/storage/members.d.ts.map +1 -1
- package/dist/storage/members.js +3 -1
- package/dist/storage/members.js.map +1 -1
- package/dist/storage/restIdempotency.d.ts +6 -0
- package/dist/storage/restIdempotency.d.ts.map +1 -1
- package/dist/storage/restIdempotency.js +8 -0
- package/dist/storage/restIdempotency.js.map +1 -1
- package/dist/storage/scheduledSends.d.ts +2 -1
- package/dist/storage/scheduledSends.d.ts.map +1 -1
- package/dist/storage/scheduledSends.js +6 -0
- package/dist/storage/scheduledSends.js.map +1 -1
- package/package.json +5 -5
package/dist/cli.js
CHANGED
|
@@ -25,13 +25,14 @@ import { VERSION } from './version.js';
|
|
|
25
25
|
import { inspectStoreCompatibility, MIN_SUPPORTED_STORE_FORMAT, openDb, openReadonlyDb, } from './storage/db.js';
|
|
26
26
|
import { customPermissionPolicy, ADMIN_CAPABILITIES, FULL_PERMISSION_POLICY, isNamedPermissionProfile, MCP_CAPABILITIES, NAMED_PERMISSION_PROFILES, permissionPolicyForProfile, } from './permissions.js';
|
|
27
27
|
import { captureOperation, getTelemetry, installTelemetryStreamEndHandler, isTelemetryEnabled, setTelemetryEnabled, shutdownTelemetry, telemetryDisabledInAnyEnvironment, } from './telemetry.js';
|
|
28
|
-
import { apiErrorCode, clearSessionToken, instanceClient, loadInstanceConfig, removeInstance, resolveInstance, saveLocalInstance, saveRemoteInstance, saveSessionToken, useInstance, } from './cliInstances.js';
|
|
28
|
+
import { apiErrorCode, apiRequestId, clearSessionToken, instanceClient, loadInstanceConfig, removeInstance, resolveInstance, saveLocalInstance, saveRemoteInstance, saveSessionToken, setRequestDeadlineMs, useInstance, } from './cliInstances.js';
|
|
29
|
+
import { cliExitCode, parseOutputFormat, printOutput } from './cliOutput.js';
|
|
29
30
|
import { authenticateBearer, isBootstrapComplete, normalizeAndValidatePassword, recoverAdminPassword, setupInitialAdmin, } from './auth.js';
|
|
30
31
|
import { recordAdminAuditEvent } from './storage/adminAudit.js';
|
|
31
32
|
import { canManageOwnedAccount } from './authorization.js';
|
|
32
33
|
import { createCliUpdateNotifier } from './updateNotifier.js';
|
|
33
34
|
import { registerMailCommands } from './cliMail.js';
|
|
34
|
-
import { accountInventoryProperties, configuredOAuthAppKind, connectionProperties } from './accounts/telemetry.js';
|
|
35
|
+
import { accountInventoryProperties, configuredOAuthAppKind, connectionProperties, instanceUsageProperties, } from './accounts/telemetry.js';
|
|
35
36
|
import { flushLogging, escapeLogTextForConsole, getLogger, logCodedFailure, logFailure, readLocalLogs, shutdownLogging, } from './logging.js';
|
|
36
37
|
function collectOption(value, previous) {
|
|
37
38
|
return [...previous, value];
|
|
@@ -178,6 +179,33 @@ function readSecretFile(file) {
|
|
|
178
179
|
async function secretInput(file, label) {
|
|
179
180
|
return file === undefined ? hiddenPrompt(label) : readSecretFile(file);
|
|
180
181
|
}
|
|
182
|
+
/** Print the consent URL and explain how to finish when the redirect cannot reach this computer. */
|
|
183
|
+
function printLoopbackInstructions(provider, url, context, port) {
|
|
184
|
+
const providerName = provider === 'gmail' ? 'Google' : 'Microsoft';
|
|
185
|
+
const access = provider === 'gmail' ? 'Gmail access' : 'Microsoft mail access';
|
|
186
|
+
console.log(`\nOpen this URL in your browser to authorize ${access}:\n`);
|
|
187
|
+
console.log(` ${url}\n`);
|
|
188
|
+
if (!context.listening) {
|
|
189
|
+
console.log(`Port ${port} is already in use, so Fluxmail cannot receive the redirect from ${providerName}.\n\n` +
|
|
190
|
+
'If Fluxmail is running with Docker Compose, press Ctrl-C and connect the account inside the container ' +
|
|
191
|
+
'so it is saved there:\n\n' +
|
|
192
|
+
` docker compose exec fluxmail fluxmail accounts add ${provider}\n\n` +
|
|
193
|
+
"Otherwise, approve access, then copy the full URL from your browser's address bar and paste it here.");
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
console.log(`Waiting for ${providerName} to redirect back...`);
|
|
197
|
+
if (context.pasteEnabled) {
|
|
198
|
+
console.log('If your browser runs on another computer, the page will not load after you approve access. ' +
|
|
199
|
+
'Copy the full URL from its address bar and paste it here.');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/** Accept a pasted callback URL when a person is at the terminal, and report how the callback arrived. */
|
|
203
|
+
function loopbackFlowOptions(program, provider) {
|
|
204
|
+
return {
|
|
205
|
+
...(process.stdin.isTTY ? { paste: { input: process.stdin, write: (message) => console.error(message) } } : {}),
|
|
206
|
+
onCallback: (callback) => recordCliOperationProperties(program, connectionProperties({ provider, callback })),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
181
209
|
/** Offered when a configured public URL, not an explicit --hosted, chose the hosted flow. */
|
|
182
210
|
const LOOPBACK_FLOW_REMEDY = 'Pass --local to use the loopback flow on this computer instead.';
|
|
183
211
|
function planLine(ent) {
|
|
@@ -248,9 +276,22 @@ function finishCliOperation(program, outcome, errorCode, error) {
|
|
|
248
276
|
}
|
|
249
277
|
/** End a failed command with the error's own telemetry code instead of a generic one. */
|
|
250
278
|
function failCliOperation(program, error, prefix = 'Error: ') {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
279
|
+
const code = apiErrorCode(error);
|
|
280
|
+
finishCliOperation(program, 'error', code, error);
|
|
281
|
+
let format = 'json';
|
|
282
|
+
try {
|
|
283
|
+
format = parseOutputFormat(program.opts().format ?? 'json');
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// Report an invalid --format value in the default structured format.
|
|
287
|
+
}
|
|
288
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
289
|
+
console.error(format === 'table'
|
|
290
|
+
? `${prefix}${message}`
|
|
291
|
+
: JSON.stringify({
|
|
292
|
+
error: { code, message, ...(apiRequestId(error) ? { requestId: apiRequestId(error) } : {}) },
|
|
293
|
+
}));
|
|
294
|
+
process.exitCode = cliExitCode(code);
|
|
254
295
|
}
|
|
255
296
|
export function waitForServerListening(server) {
|
|
256
297
|
return new Promise((resolve, reject) => {
|
|
@@ -295,10 +336,14 @@ export function createCliProgram(options = {}) {
|
|
|
295
336
|
.description('Fluxmail, a self-hosted email API with MCP, REST, and CLI access')
|
|
296
337
|
.option('--instance <name>', 'Use a named local or remote instance')
|
|
297
338
|
.option('-a, --mail-account <id-or-email>', 'Use an email account by ID or address')
|
|
339
|
+
.option('--format <format>', 'Output format: json, table, or ndjson', 'json')
|
|
340
|
+
.option('--timeout <seconds>', 'Request deadline in seconds (1 to 300)', '30')
|
|
298
341
|
.option('--no-update-notifier', 'Skip the automatic update check for this command')
|
|
299
342
|
.version(VERSION, '-v, --version');
|
|
300
343
|
const selectedInstance = () => program.opts().instance;
|
|
301
344
|
const selectedAccount = () => program.opts().mailAccount;
|
|
345
|
+
const selectedFormat = () => parseOutputFormat(program.opts().format);
|
|
346
|
+
const capturedOutput = new Map();
|
|
302
347
|
function commandPath(command) {
|
|
303
348
|
const names = [];
|
|
304
349
|
for (let current = command; current?.parent; current = current.parent)
|
|
@@ -337,6 +382,8 @@ export function createCliProgram(options = {}) {
|
|
|
337
382
|
process.once('SIGHUP', onSighup);
|
|
338
383
|
}
|
|
339
384
|
program.hook('preAction', (_command, actionCommand) => {
|
|
385
|
+
selectedFormat();
|
|
386
|
+
setRequestDeadlineMs(Number(program.opts().timeout) * 1000);
|
|
340
387
|
const command = commandPath(actionCommand);
|
|
341
388
|
const updateNotifierEnabled = program.opts().updateNotifier;
|
|
342
389
|
if (updateNotifierEnabled && actionCommand.name() !== 'stdio') {
|
|
@@ -390,8 +437,44 @@ export function createCliProgram(options = {}) {
|
|
|
390
437
|
initialExitCode: process.exitCode,
|
|
391
438
|
logger: getLogger(dataDir, mode, logging),
|
|
392
439
|
});
|
|
440
|
+
const [group, action] = command.split(' ');
|
|
441
|
+
const alreadyStructured = ['folders', 'labels', 'emails', 'threads', 'drafts', 'scheduled', 'attachments'].includes(group ?? '') ||
|
|
442
|
+
command === 'accounts list' ||
|
|
443
|
+
command === 'status';
|
|
444
|
+
const interactive = ['setup', 'login', 'serve', 'stdio'].includes(command) ||
|
|
445
|
+
group === 'auth' ||
|
|
446
|
+
command === 'accounts add' ||
|
|
447
|
+
command === 'accounts configure' ||
|
|
448
|
+
command === 'license activate' ||
|
|
449
|
+
(group === 'oauth' && action !== 'status') ||
|
|
450
|
+
group === 'logs';
|
|
451
|
+
if (selectedFormat() !== 'table' && !alreadyStructured && !interactive) {
|
|
452
|
+
const original = console.log;
|
|
453
|
+
const lines = [];
|
|
454
|
+
capturedOutput.set(program, { original, lines });
|
|
455
|
+
console.log = (...values) => {
|
|
456
|
+
lines.push(values.map((value) => (typeof value === 'string' ? value : JSON.stringify(value))).join(' '));
|
|
457
|
+
};
|
|
458
|
+
}
|
|
393
459
|
});
|
|
394
460
|
program.hook('postAction', async (_command, actionCommand) => {
|
|
461
|
+
const captured = capturedOutput.get(program);
|
|
462
|
+
if (captured) {
|
|
463
|
+
capturedOutput.delete(program);
|
|
464
|
+
console.log = captured.original;
|
|
465
|
+
if (captured.lines.length) {
|
|
466
|
+
let data = captured.lines.length === 1 ? captured.lines[0] : captured.lines;
|
|
467
|
+
if (captured.lines.length === 1) {
|
|
468
|
+
try {
|
|
469
|
+
data = JSON.parse(captured.lines[0]);
|
|
470
|
+
}
|
|
471
|
+
catch {
|
|
472
|
+
/* Plain output stays a string. */
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
printOutput({ data }, selectedFormat());
|
|
476
|
+
}
|
|
477
|
+
}
|
|
395
478
|
const active = activeCliOperations.get(program);
|
|
396
479
|
const failed = active !== undefined &&
|
|
397
480
|
process.exitCode !== active.initialExitCode &&
|
|
@@ -638,7 +721,11 @@ export function createCliProgram(options = {}) {
|
|
|
638
721
|
details: { port: ctx.config.port },
|
|
639
722
|
skipConsole: true,
|
|
640
723
|
});
|
|
641
|
-
ctx.telemetry.capture('mcp server started', {
|
|
724
|
+
ctx.telemetry.capture('mcp server started', {
|
|
725
|
+
...instanceUsageProperties(ctx.db),
|
|
726
|
+
product_surface: 'mcp',
|
|
727
|
+
transport: 'http',
|
|
728
|
+
});
|
|
642
729
|
console.log(`Fluxmail listening on ${ctx.config.publicUrl}`);
|
|
643
730
|
console.log(` MCP endpoint: ${ctx.config.publicUrl}/mcp`);
|
|
644
731
|
console.log(` REST API: ${ctx.config.publicUrl}/api/v1`);
|
|
@@ -692,7 +779,11 @@ export function createCliProgram(options = {}) {
|
|
|
692
779
|
});
|
|
693
780
|
ctx.scheduler.start();
|
|
694
781
|
await server.connect(new StdioServerTransport());
|
|
695
|
-
ctx.telemetry.capture('mcp server started', {
|
|
782
|
+
ctx.telemetry.capture('mcp server started', {
|
|
783
|
+
...instanceUsageProperties(ctx.db),
|
|
784
|
+
product_surface: 'mcp',
|
|
785
|
+
transport: 'stdio',
|
|
786
|
+
});
|
|
696
787
|
ctx.logger.info('server.started', 'Fluxmail stdio MCP server started', {
|
|
697
788
|
productSurface: 'mcp',
|
|
698
789
|
details: { transport: 'stdio' },
|
|
@@ -979,11 +1070,7 @@ export function createCliProgram(options = {}) {
|
|
|
979
1070
|
console.log('This link expires in 10 minutes and can only be used once.');
|
|
980
1071
|
return;
|
|
981
1072
|
}
|
|
982
|
-
const account = await runMicrosoftLoopbackFlow(ctx.config, (url) => {
|
|
983
|
-
console.log('\nOpen this URL in your browser to authorize Microsoft mail access:\n');
|
|
984
|
-
console.log(` ${url}\n`);
|
|
985
|
-
console.log('Waiting for Microsoft to redirect back...');
|
|
986
|
-
}, (result) => {
|
|
1073
|
+
const account = await runMicrosoftLoopbackFlow(ctx.config, (url, context) => printLoopbackInstructions('outlook', url, context, ctx.config.oauthPort), (result) => {
|
|
987
1074
|
const duplicate = ctx.registry
|
|
988
1075
|
.listAccounts()
|
|
989
1076
|
.find((candidate) => candidate.email.toLowerCase() === result.email.toLowerCase());
|
|
@@ -995,7 +1082,7 @@ export function createCliProgram(options = {}) {
|
|
|
995
1082
|
'Try again and choose the matching Microsoft account.');
|
|
996
1083
|
}
|
|
997
1084
|
return ctx.registry.addOutlookAccount(result.email, result.credentials, result.displayName, owner.id, existing?.id, access);
|
|
998
|
-
});
|
|
1085
|
+
}, loopbackFlowOptions(program, 'outlook'));
|
|
999
1086
|
auditConnection('account.connection.complete', account.id);
|
|
1000
1087
|
recordCliOperationProperties(program, {
|
|
1001
1088
|
reauthorize: accountIdsBeforeConnection.has(account.id),
|
|
@@ -1018,11 +1105,7 @@ export function createCliProgram(options = {}) {
|
|
|
1018
1105
|
console.log('This link expires in 10 minutes and can only be used once.');
|
|
1019
1106
|
return;
|
|
1020
1107
|
}
|
|
1021
|
-
const account = await runLoopbackFlow(ctx.config, (url) => {
|
|
1022
|
-
console.log('\nOpen this URL in your browser to authorize Gmail access:\n');
|
|
1023
|
-
console.log(` ${url}\n`);
|
|
1024
|
-
console.log('Waiting for Google to redirect back…');
|
|
1025
|
-
}, (result) => {
|
|
1108
|
+
const account = await runLoopbackFlow(ctx.config, (url, context) => printLoopbackInstructions('gmail', url, context, ctx.config.oauthPort), (result) => {
|
|
1026
1109
|
const duplicate = ctx.registry
|
|
1027
1110
|
.listAccounts()
|
|
1028
1111
|
.find((candidate) => candidate.email.toLowerCase() === result.email.toLowerCase());
|
|
@@ -1034,7 +1117,7 @@ export function createCliProgram(options = {}) {
|
|
|
1034
1117
|
'Try again and choose the matching Google account.');
|
|
1035
1118
|
}
|
|
1036
1119
|
return ctx.registry.addGmailAccount(result.email, result.tokens, result.displayName, owner.id, access, result.oauthClient);
|
|
1037
|
-
});
|
|
1120
|
+
}, loopbackFlowOptions(program, 'gmail'));
|
|
1038
1121
|
auditConnection('account.connection.complete', account.id);
|
|
1039
1122
|
recordCliOperationProperties(program, {
|
|
1040
1123
|
reauthorize: accountIdsBeforeConnection.has(account.id),
|
|
@@ -1097,18 +1180,7 @@ export function createCliProgram(options = {}) {
|
|
|
1097
1180
|
.action(async () => {
|
|
1098
1181
|
try {
|
|
1099
1182
|
const all = await instanceClient(selectedInstance()).json('/api/v1/accounts');
|
|
1100
|
-
|
|
1101
|
-
console.log('No accounts connected. Run "fluxmail accounts add <provider>".');
|
|
1102
|
-
return;
|
|
1103
|
-
}
|
|
1104
|
-
for (const a of all) {
|
|
1105
|
-
const access = a.sharedWithAll
|
|
1106
|
-
? 'all'
|
|
1107
|
-
: a.grantedMemberIds.length
|
|
1108
|
-
? `selected:${a.grantedMemberIds.join(',')}`
|
|
1109
|
-
: 'owner-only';
|
|
1110
|
-
console.log(`${a.id} ${a.provider} ${a.email} [${a.status}] owner=${a.ownerMemberId} access=${access}`);
|
|
1111
|
-
}
|
|
1183
|
+
printOutput({ data: all }, selectedFormat());
|
|
1112
1184
|
}
|
|
1113
1185
|
catch (err) {
|
|
1114
1186
|
failCliOperation(program, err);
|
|
@@ -1188,7 +1260,7 @@ export function createCliProgram(options = {}) {
|
|
|
1188
1260
|
.requiredOption('--name <name>', 'Member name')
|
|
1189
1261
|
.requiredOption('--email <email>', 'Member login email')
|
|
1190
1262
|
.option('--role <role>', 'Member role: admin or member')
|
|
1191
|
-
.description(
|
|
1263
|
+
.description("Add a member (subject to your plan's member limit)")
|
|
1192
1264
|
.action(async (opts) => {
|
|
1193
1265
|
try {
|
|
1194
1266
|
if (opts.role && opts.role !== 'admin' && opts.role !== 'member') {
|
|
@@ -1752,14 +1824,20 @@ export function createCliProgram(options = {}) {
|
|
|
1752
1824
|
registerMailCommands(program, {
|
|
1753
1825
|
selectedInstance,
|
|
1754
1826
|
selectedAccount,
|
|
1827
|
+
selectedFormat,
|
|
1755
1828
|
reportError: (error, code) => {
|
|
1756
1829
|
finishCliOperation(program, 'error', code, error);
|
|
1757
|
-
|
|
1758
|
-
|
|
1830
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1831
|
+
console.error(selectedFormat() === 'table'
|
|
1832
|
+
? `Error [${code}]: ${message}`
|
|
1833
|
+
: JSON.stringify({
|
|
1834
|
+
error: { code, message, ...(apiRequestId(error) ? { requestId: apiRequestId(error) } : {}) },
|
|
1835
|
+
}));
|
|
1836
|
+
process.exitCode = cliExitCode(code);
|
|
1759
1837
|
},
|
|
1760
1838
|
reportPartialFailure: (code) => {
|
|
1761
1839
|
finishCliOperation(program, 'error', code);
|
|
1762
|
-
process.exitCode =
|
|
1840
|
+
process.exitCode = cliExitCode(code);
|
|
1763
1841
|
},
|
|
1764
1842
|
});
|
|
1765
1843
|
program
|
|
@@ -1768,7 +1846,7 @@ export function createCliProgram(options = {}) {
|
|
|
1768
1846
|
.action(async () => {
|
|
1769
1847
|
try {
|
|
1770
1848
|
const status = await instanceClient(selectedInstance()).json('/api/v1/status');
|
|
1771
|
-
|
|
1849
|
+
printOutput({ data: status }, selectedFormat());
|
|
1772
1850
|
}
|
|
1773
1851
|
catch (err) {
|
|
1774
1852
|
failCliOperation(program, err);
|