@getmagical/cli 0.1.5 → 0.1.6
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 +16 -16
- package/dist/index.js +375 -184
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1276,7 +1276,7 @@ mutation UpdateAutomationById($id: ID!, $input: UpdateAutomationInput!) {
|
|
|
1276
1276
|
];
|
|
1277
1277
|
|
|
1278
1278
|
// src/program.ts
|
|
1279
|
-
import { Command, InvalidArgumentError, Option } from "commander";
|
|
1279
|
+
import { Command as Command2, InvalidArgumentError as InvalidArgumentError2, Option as Option2 } from "commander";
|
|
1280
1280
|
|
|
1281
1281
|
// src/api.ts
|
|
1282
1282
|
import { z as z2 } from "zod";
|
|
@@ -1323,15 +1323,20 @@ function getApiErrorDetail(responseBody) {
|
|
|
1323
1323
|
}
|
|
1324
1324
|
return parsedResponse.data.errors.map((error) => error.message).join("\n");
|
|
1325
1325
|
}
|
|
1326
|
+
function trimTrailingSlash(value) {
|
|
1327
|
+
return value.replace(/\/+$/u, "");
|
|
1328
|
+
}
|
|
1326
1329
|
function createMagicalApiClient({
|
|
1327
1330
|
apiBaseUrl,
|
|
1328
1331
|
fetchFn = fetch
|
|
1329
1332
|
}) {
|
|
1333
|
+
const resolveApiBaseUrl = typeof apiBaseUrl === "string" ? () => apiBaseUrl : apiBaseUrl;
|
|
1330
1334
|
async function fetchJson({
|
|
1331
1335
|
accessToken,
|
|
1332
|
-
|
|
1336
|
+
path: path5,
|
|
1333
1337
|
init
|
|
1334
1338
|
}) {
|
|
1339
|
+
const url = `${trimTrailingSlash(await resolveApiBaseUrl())}${path5}`;
|
|
1335
1340
|
const headers = new Headers(init?.headers);
|
|
1336
1341
|
headers.set("authorization", `Bearer ${accessToken}`);
|
|
1337
1342
|
const response = await fetchFn(url, {
|
|
@@ -1339,7 +1344,7 @@ function createMagicalApiClient({
|
|
|
1339
1344
|
headers
|
|
1340
1345
|
}).catch((error) => {
|
|
1341
1346
|
throw new CliError(
|
|
1342
|
-
`Failed to reach Magical API at ${url}. Check
|
|
1347
|
+
`Failed to reach Magical API at ${url}. Check your configured base URL and make sure service-main is running.`,
|
|
1343
1348
|
{ cause: error }
|
|
1344
1349
|
);
|
|
1345
1350
|
});
|
|
@@ -1379,7 +1384,7 @@ function createMagicalApiClient({
|
|
|
1379
1384
|
const parsedResponse = graphQlResponseSchema.safeParse(
|
|
1380
1385
|
await fetchJson({
|
|
1381
1386
|
accessToken,
|
|
1382
|
-
|
|
1387
|
+
path: "/graphql",
|
|
1383
1388
|
init: {
|
|
1384
1389
|
method: "POST",
|
|
1385
1390
|
headers,
|
|
@@ -1404,7 +1409,7 @@ function createMagicalApiClient({
|
|
|
1404
1409
|
const parsedResponse = workosOrganizationsResponseSchema.safeParse(
|
|
1405
1410
|
await fetchJson({
|
|
1406
1411
|
accessToken,
|
|
1407
|
-
|
|
1412
|
+
path: "/workos/organizations"
|
|
1408
1413
|
})
|
|
1409
1414
|
);
|
|
1410
1415
|
if (!parsedResponse.success) {
|
|
@@ -1423,7 +1428,7 @@ function createMagicalApiClient({
|
|
|
1423
1428
|
const parsedResponse = workosUserSchema.safeParse(
|
|
1424
1429
|
await fetchJson({
|
|
1425
1430
|
accessToken,
|
|
1426
|
-
|
|
1431
|
+
path: `/workos/user/${userId}`
|
|
1427
1432
|
})
|
|
1428
1433
|
);
|
|
1429
1434
|
if (!parsedResponse.success) {
|
|
@@ -1434,57 +1439,19 @@ function createMagicalApiClient({
|
|
|
1434
1439
|
};
|
|
1435
1440
|
}
|
|
1436
1441
|
|
|
1437
|
-
// src/command-presentation.ts
|
|
1438
|
-
var rootOperationalGroupDescriptions = /* @__PURE__ */ new Map([
|
|
1439
|
-
["agents", "Query agents."],
|
|
1440
|
-
["agent-runs", "Query agent runs."],
|
|
1441
|
-
["automations", "Manage automations."],
|
|
1442
|
-
["automation-runs", "Inspect and control automation runs."],
|
|
1443
|
-
["catalog", "Inspect available commands, models, and tools."],
|
|
1444
|
-
["graphql", "Inspect GraphQL metadata."]
|
|
1445
|
-
]);
|
|
1446
|
-
function configureCommandPresentation(command) {
|
|
1447
|
-
const originalCreateCommand = command.createCommand.bind(command);
|
|
1448
|
-
command.createCommand = (name) => configureCommandPresentation(originalCreateCommand(name));
|
|
1449
|
-
command.createHelp = () => new MagicalHelp();
|
|
1450
|
-
return command;
|
|
1451
|
-
}
|
|
1452
|
-
function createOperationHelpExamples(operationSpec) {
|
|
1453
|
-
const baseCommand = `mgcl ${operationSpec.cli.path.join(" ")}`;
|
|
1454
|
-
const requiredOptions = operationSpec.cli.options.filter((optionSpec) => optionSpec.required).map((optionSpec) => {
|
|
1455
|
-
if (optionSpec.valueType === "boolean") {
|
|
1456
|
-
return `--${optionSpec.flagName}`;
|
|
1457
|
-
}
|
|
1458
|
-
if (optionSpec.valueType === "number") {
|
|
1459
|
-
return `--${optionSpec.flagName} 10`;
|
|
1460
|
-
}
|
|
1461
|
-
if (optionSpec.valueType === "json") {
|
|
1462
|
-
return `--${optionSpec.flagName} '{...}'`;
|
|
1463
|
-
}
|
|
1464
|
-
if (optionSpec.valueType === "string-array") {
|
|
1465
|
-
return `--${optionSpec.flagName} value-a,value-b`;
|
|
1466
|
-
}
|
|
1467
|
-
return `--${optionSpec.flagName} <${optionSpec.flagName}>`;
|
|
1468
|
-
});
|
|
1469
|
-
const baseInvocation = [baseCommand, ...requiredOptions].join(" ");
|
|
1470
|
-
return [
|
|
1471
|
-
baseInvocation,
|
|
1472
|
-
`${baseInvocation} --org <org>`,
|
|
1473
|
-
`${baseInvocation} --json`
|
|
1474
|
-
];
|
|
1475
|
-
}
|
|
1476
|
-
|
|
1477
1442
|
// src/config.ts
|
|
1478
1443
|
import os from "os";
|
|
1479
1444
|
import path from "path";
|
|
1480
1445
|
var DEFAULT_MAGICAL_API_URL = "https://api-agt.getmagical.io";
|
|
1481
1446
|
var DEFAULT_WORKOS_API_URL = "https://api.workos.com";
|
|
1482
1447
|
var DEFAULT_WORKOS_CLIENT_ID = "client_01JJZ6XJ1RF248P20WF63M4VAM";
|
|
1448
|
+
var DEFAULT_STAGING_WORKOS_CLIENT_ID = "client_01JJZ6X26BGFBT8AC303XPQ9EQ";
|
|
1483
1449
|
var DEFAULT_KEYCHAIN_SERVICE_NAME = "@getmagical/mcp-cli";
|
|
1484
1450
|
var DEFAULT_CLI_DIST_TAG = "latest";
|
|
1485
1451
|
var DEFAULT_CLI_NPM_REGISTRY_URL = "https://registry.npmjs.org/";
|
|
1486
1452
|
var CLI_CONFIG_DIRECTORY_NAME = "magical-mcp-cli";
|
|
1487
1453
|
var CLI_STATE_FILE_NAME = "state.json";
|
|
1454
|
+
var CLI_SETTINGS_FILE_NAME = "settings.json";
|
|
1488
1455
|
function resolvePlatformConfigDirectory() {
|
|
1489
1456
|
const customConfigDirectory = process.env["MAGICAL_CLI_CONFIG_DIR"];
|
|
1490
1457
|
if (customConfigDirectory) {
|
|
@@ -1506,19 +1473,202 @@ function getRuntimeConfig() {
|
|
|
1506
1473
|
);
|
|
1507
1474
|
return {
|
|
1508
1475
|
cliDistTag: process.env["MAGICAL_CLI_DIST_TAG"] ?? DEFAULT_CLI_DIST_TAG,
|
|
1509
|
-
magicalApiUrl:
|
|
1476
|
+
magicalApiUrl: DEFAULT_MAGICAL_API_URL,
|
|
1510
1477
|
npmRegistryUrl: process.env["MAGICAL_CLI_NPM_REGISTRY_URL"] ?? DEFAULT_CLI_NPM_REGISTRY_URL,
|
|
1511
1478
|
stateFilePath: path.join(configDirectory, CLI_STATE_FILE_NAME),
|
|
1512
1479
|
workosApiUrl: DEFAULT_WORKOS_API_URL,
|
|
1513
|
-
workosClientId:
|
|
1514
|
-
keychainServiceName: DEFAULT_KEYCHAIN_SERVICE_NAME
|
|
1515
|
-
...process.env["WORKOS_AUTHKIT_DOMAIN"] ? { workosAuthkitDomain: process.env["WORKOS_AUTHKIT_DOMAIN"] } : {}
|
|
1480
|
+
workosClientId: DEFAULT_WORKOS_CLIENT_ID,
|
|
1481
|
+
keychainServiceName: DEFAULT_KEYCHAIN_SERVICE_NAME
|
|
1516
1482
|
};
|
|
1517
1483
|
}
|
|
1518
1484
|
function requireWorkosClientId(config) {
|
|
1519
1485
|
return config.workosClientId;
|
|
1520
1486
|
}
|
|
1521
1487
|
|
|
1488
|
+
// src/settings.ts
|
|
1489
|
+
import { mkdir, readFile, rm, writeFile } from "fs/promises";
|
|
1490
|
+
import path2 from "path";
|
|
1491
|
+
import { safeJsonParse } from "@magical/common/stdlib/json.util";
|
|
1492
|
+
import { isErr } from "@magical/common/stdlib/result.util";
|
|
1493
|
+
import { z as z3 } from "zod";
|
|
1494
|
+
var cliSettingsSchema = z3.object({
|
|
1495
|
+
env: z3.object({
|
|
1496
|
+
baseUrl: z3.url().optional()
|
|
1497
|
+
}).default({})
|
|
1498
|
+
});
|
|
1499
|
+
function createEmptyCliSettings() {
|
|
1500
|
+
return {
|
|
1501
|
+
env: {}
|
|
1502
|
+
};
|
|
1503
|
+
}
|
|
1504
|
+
function hasCliSettingsOverrides(settings) {
|
|
1505
|
+
return settings.env.baseUrl !== void 0;
|
|
1506
|
+
}
|
|
1507
|
+
function resolveSettingsFilePath(stateFilePath) {
|
|
1508
|
+
return path2.join(path2.dirname(stateFilePath), CLI_SETTINGS_FILE_NAME);
|
|
1509
|
+
}
|
|
1510
|
+
function resolveConfiguredApiBaseUrl({
|
|
1511
|
+
defaultApiBaseUrl,
|
|
1512
|
+
settings
|
|
1513
|
+
}) {
|
|
1514
|
+
return settings.env.baseUrl ?? defaultApiBaseUrl;
|
|
1515
|
+
}
|
|
1516
|
+
function shouldUseStagingWorkosClientId(settings) {
|
|
1517
|
+
return settings.env.baseUrl !== void 0;
|
|
1518
|
+
}
|
|
1519
|
+
function createFileSettingsStore(stateFilePath) {
|
|
1520
|
+
const settingsFilePath = resolveSettingsFilePath(stateFilePath);
|
|
1521
|
+
return {
|
|
1522
|
+
async load() {
|
|
1523
|
+
const fileContents = await readFile(settingsFilePath, "utf8").catch(
|
|
1524
|
+
(error) => {
|
|
1525
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
1526
|
+
return null;
|
|
1527
|
+
}
|
|
1528
|
+
throw new CliError("Failed to load CLI settings.", { cause: error });
|
|
1529
|
+
}
|
|
1530
|
+
);
|
|
1531
|
+
if (fileContents === null) {
|
|
1532
|
+
return createEmptyCliSettings();
|
|
1533
|
+
}
|
|
1534
|
+
const parsedJson = safeJsonParse(fileContents);
|
|
1535
|
+
if (isErr(parsedJson)) {
|
|
1536
|
+
throw new CliError("Stored CLI settings are invalid.", {
|
|
1537
|
+
cause: parsedJson.error.cause
|
|
1538
|
+
});
|
|
1539
|
+
}
|
|
1540
|
+
const parsed = cliSettingsSchema.safeParse(parsedJson.value);
|
|
1541
|
+
if (!parsed.success) {
|
|
1542
|
+
throw new CliError("Stored CLI settings are invalid.", {
|
|
1543
|
+
cause: parsed.error
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1546
|
+
return parsed.data;
|
|
1547
|
+
},
|
|
1548
|
+
async save(settings) {
|
|
1549
|
+
if (!hasCliSettingsOverrides(settings)) {
|
|
1550
|
+
await rm(settingsFilePath, { force: true });
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
await mkdir(path2.dirname(settingsFilePath), { recursive: true });
|
|
1554
|
+
await writeFile(
|
|
1555
|
+
settingsFilePath,
|
|
1556
|
+
`${JSON.stringify(settings, null, 2)}
|
|
1557
|
+
`
|
|
1558
|
+
);
|
|
1559
|
+
}
|
|
1560
|
+
};
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
// src/auth-login.ts
|
|
1564
|
+
function writeJsonOutput(io, value) {
|
|
1565
|
+
io.info(JSON.stringify(value, null, 2));
|
|
1566
|
+
}
|
|
1567
|
+
async function handleAuthLogin(dependencies, options) {
|
|
1568
|
+
const settings = await dependencies.settingsStore?.load() ?? createEmptyCliSettings();
|
|
1569
|
+
const clientId = shouldUseStagingWorkosClientId(settings) ? DEFAULT_STAGING_WORKOS_CLIENT_ID : requireWorkosClientId(dependencies.runtimeConfig);
|
|
1570
|
+
const deviceAuthorization = await dependencies.authClient.startDeviceAuthorization({ clientId });
|
|
1571
|
+
const verificationUrl = deviceAuthorization.verification_uri_complete ?? deviceAuthorization.verification_uri;
|
|
1572
|
+
const promptWriter = options.json ? dependencies.io.error : dependencies.io.info;
|
|
1573
|
+
promptWriter(
|
|
1574
|
+
formatAuthLoginPrompt({
|
|
1575
|
+
userCode: deviceAuthorization.user_code,
|
|
1576
|
+
verificationUrl
|
|
1577
|
+
})
|
|
1578
|
+
);
|
|
1579
|
+
await dependencies.openExternalUrl(verificationUrl).catch(() => {
|
|
1580
|
+
promptWriter(formatBrowserOpenFallback());
|
|
1581
|
+
});
|
|
1582
|
+
const tokenResponse = await dependencies.authClient.pollForDeviceTokens({
|
|
1583
|
+
clientId,
|
|
1584
|
+
deviceCode: deviceAuthorization.device_code,
|
|
1585
|
+
...deviceAuthorization.expires_in ? { expiresInSeconds: deviceAuthorization.expires_in } : {},
|
|
1586
|
+
...deviceAuthorization.interval ? { intervalSeconds: deviceAuthorization.interval } : {}
|
|
1587
|
+
});
|
|
1588
|
+
const accessTokenClaims = dependencies.authClient.decodeAccessTokenClaims(
|
|
1589
|
+
tokenResponse.access_token
|
|
1590
|
+
);
|
|
1591
|
+
const [user, organizations] = await Promise.all([
|
|
1592
|
+
dependencies.apiClient.fetchUser({
|
|
1593
|
+
accessToken: tokenResponse.access_token,
|
|
1594
|
+
userId: accessTokenClaims.sub
|
|
1595
|
+
}),
|
|
1596
|
+
dependencies.apiClient.fetchOrganizations({
|
|
1597
|
+
accessToken: tokenResponse.access_token
|
|
1598
|
+
})
|
|
1599
|
+
]);
|
|
1600
|
+
const defaultOrgId = accessTokenClaims.org_id ?? organizations[0]?.id ?? null;
|
|
1601
|
+
const nextState = {
|
|
1602
|
+
account: {
|
|
1603
|
+
clientId,
|
|
1604
|
+
email: user.email,
|
|
1605
|
+
userId: user.id
|
|
1606
|
+
},
|
|
1607
|
+
defaultOrgId,
|
|
1608
|
+
lastUsedOrgId: defaultOrgId,
|
|
1609
|
+
organizations
|
|
1610
|
+
};
|
|
1611
|
+
await Promise.all([
|
|
1612
|
+
dependencies.refreshTokenStore.save(
|
|
1613
|
+
nextState.account,
|
|
1614
|
+
tokenResponse.refresh_token
|
|
1615
|
+
),
|
|
1616
|
+
dependencies.stateStore.save(nextState)
|
|
1617
|
+
]);
|
|
1618
|
+
const defaultOrganization = organizations.find((organization) => organization.id === defaultOrgId) ?? null;
|
|
1619
|
+
if (options.json) {
|
|
1620
|
+
writeJsonOutput(dependencies.io, nextState);
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
dependencies.io.info(
|
|
1624
|
+
formatAuthLoginSuccess({
|
|
1625
|
+
account: nextState.account,
|
|
1626
|
+
defaultOrganization,
|
|
1627
|
+
organizationCount: organizations.length
|
|
1628
|
+
})
|
|
1629
|
+
);
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
// src/command-presentation.ts
|
|
1633
|
+
var rootOperationalGroupDescriptions = /* @__PURE__ */ new Map([
|
|
1634
|
+
["agents", "Query agents."],
|
|
1635
|
+
["agent-runs", "Query agent runs."],
|
|
1636
|
+
["automations", "Manage automations."],
|
|
1637
|
+
["automation-runs", "Inspect and control automation runs."],
|
|
1638
|
+
["catalog", "Inspect available commands, models, and tools."],
|
|
1639
|
+
["graphql", "Inspect GraphQL metadata."]
|
|
1640
|
+
]);
|
|
1641
|
+
function configureCommandPresentation(command) {
|
|
1642
|
+
const originalCreateCommand = command.createCommand.bind(command);
|
|
1643
|
+
command.createCommand = (name) => configureCommandPresentation(originalCreateCommand(name));
|
|
1644
|
+
command.createHelp = () => new MagicalHelp();
|
|
1645
|
+
return command;
|
|
1646
|
+
}
|
|
1647
|
+
function createOperationHelpExamples(operationSpec) {
|
|
1648
|
+
const baseCommand = `mgcl ${operationSpec.cli.path.join(" ")}`;
|
|
1649
|
+
const requiredOptions = operationSpec.cli.options.filter((optionSpec) => optionSpec.required).map((optionSpec) => {
|
|
1650
|
+
if (optionSpec.valueType === "boolean") {
|
|
1651
|
+
return `--${optionSpec.flagName}`;
|
|
1652
|
+
}
|
|
1653
|
+
if (optionSpec.valueType === "number") {
|
|
1654
|
+
return `--${optionSpec.flagName} 10`;
|
|
1655
|
+
}
|
|
1656
|
+
if (optionSpec.valueType === "json") {
|
|
1657
|
+
return `--${optionSpec.flagName} '{...}'`;
|
|
1658
|
+
}
|
|
1659
|
+
if (optionSpec.valueType === "string-array") {
|
|
1660
|
+
return `--${optionSpec.flagName} value-a,value-b`;
|
|
1661
|
+
}
|
|
1662
|
+
return `--${optionSpec.flagName} <${optionSpec.flagName}>`;
|
|
1663
|
+
});
|
|
1664
|
+
const baseInvocation = [baseCommand, ...requiredOptions].join(" ");
|
|
1665
|
+
return [
|
|
1666
|
+
baseInvocation,
|
|
1667
|
+
`${baseInvocation} --org <org>`,
|
|
1668
|
+
`${baseInvocation} --json`
|
|
1669
|
+
];
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1522
1672
|
// src/keychain.ts
|
|
1523
1673
|
import keytar from "keytar";
|
|
1524
1674
|
function buildKeychainAccountName(account) {
|
|
@@ -1574,7 +1724,7 @@ function resolveOpenCommand(url) {
|
|
|
1574
1724
|
// src/self-update.ts
|
|
1575
1725
|
import { spawn as spawn2 } from "child_process";
|
|
1576
1726
|
import fs from "fs";
|
|
1577
|
-
import
|
|
1727
|
+
import path3 from "path";
|
|
1578
1728
|
import { fileURLToPath } from "url";
|
|
1579
1729
|
var CLI_PACKAGE_NAME = "@getmagical/cli";
|
|
1580
1730
|
var DEFAULT_CLI_DIST_TAG2 = "latest";
|
|
@@ -1585,9 +1735,9 @@ function resolveInstalledPackageRoot({
|
|
|
1585
1735
|
packageName
|
|
1586
1736
|
}) {
|
|
1587
1737
|
const packagePathSegments = packageName.split("/");
|
|
1588
|
-
let currentPath =
|
|
1738
|
+
let currentPath = path3.dirname(entryFilePath);
|
|
1589
1739
|
for (; ; ) {
|
|
1590
|
-
const currentPathSegments = currentPath.split(
|
|
1740
|
+
const currentPathSegments = currentPath.split(path3.sep).filter(Boolean);
|
|
1591
1741
|
const currentPackageSegments = currentPathSegments.slice(
|
|
1592
1742
|
-packagePathSegments.length
|
|
1593
1743
|
);
|
|
@@ -1596,7 +1746,7 @@ function resolveInstalledPackageRoot({
|
|
|
1596
1746
|
)) {
|
|
1597
1747
|
return currentPath;
|
|
1598
1748
|
}
|
|
1599
|
-
const parentPath =
|
|
1749
|
+
const parentPath = path3.dirname(currentPath);
|
|
1600
1750
|
if (parentPath === currentPath) {
|
|
1601
1751
|
return null;
|
|
1602
1752
|
}
|
|
@@ -1606,14 +1756,14 @@ function resolveInstalledPackageRoot({
|
|
|
1606
1756
|
function resolveInstallPrefixFromPackageRoot(packageRootPath) {
|
|
1607
1757
|
let currentPath = packageRootPath;
|
|
1608
1758
|
for (; ; ) {
|
|
1609
|
-
if (
|
|
1610
|
-
const nodeModulesParentPath =
|
|
1611
|
-
if (
|
|
1612
|
-
return
|
|
1759
|
+
if (path3.basename(currentPath) === "node_modules") {
|
|
1760
|
+
const nodeModulesParentPath = path3.dirname(currentPath);
|
|
1761
|
+
if (path3.basename(nodeModulesParentPath) === "lib") {
|
|
1762
|
+
return path3.dirname(nodeModulesParentPath);
|
|
1613
1763
|
}
|
|
1614
1764
|
return nodeModulesParentPath;
|
|
1615
1765
|
}
|
|
1616
|
-
const parentPath =
|
|
1766
|
+
const parentPath = path3.dirname(currentPath);
|
|
1617
1767
|
if (parentPath === currentPath) {
|
|
1618
1768
|
return null;
|
|
1619
1769
|
}
|
|
@@ -1630,13 +1780,13 @@ function resolveManagedNpmCommand(installPrefix) {
|
|
|
1630
1780
|
if (process.platform === "win32") {
|
|
1631
1781
|
return null;
|
|
1632
1782
|
}
|
|
1633
|
-
const managedNodeExecutable =
|
|
1783
|
+
const managedNodeExecutable = path3.join(
|
|
1634
1784
|
installPrefix,
|
|
1635
1785
|
MANAGED_NODE_SUBPATH,
|
|
1636
1786
|
"bin",
|
|
1637
1787
|
"node"
|
|
1638
1788
|
);
|
|
1639
|
-
const managedNpmCli =
|
|
1789
|
+
const managedNpmCli = path3.join(
|
|
1640
1790
|
installPrefix,
|
|
1641
1791
|
MANAGED_NODE_SUBPATH,
|
|
1642
1792
|
"lib",
|
|
@@ -1734,34 +1884,135 @@ async function selfUpdateInstalledCli({
|
|
|
1734
1884
|
});
|
|
1735
1885
|
}
|
|
1736
1886
|
|
|
1887
|
+
// src/settings-command.ts
|
|
1888
|
+
import { isErr as isErr2 } from "@magical/common/stdlib/result.util";
|
|
1889
|
+
import { safeUrlConstructor } from "@magical/common/stdlib/url.utils";
|
|
1890
|
+
import { Command, InvalidArgumentError, Option } from "commander";
|
|
1891
|
+
function writeJsonOutput2(io, value) {
|
|
1892
|
+
io.info(JSON.stringify(value, null, 2));
|
|
1893
|
+
}
|
|
1894
|
+
function requireSettingsStore(settingsStore) {
|
|
1895
|
+
if (!settingsStore) {
|
|
1896
|
+
throw new CliError("CLI settings are not configured for this instance.");
|
|
1897
|
+
}
|
|
1898
|
+
return settingsStore;
|
|
1899
|
+
}
|
|
1900
|
+
function parseBaseUrl(value) {
|
|
1901
|
+
const parsedUrl = safeUrlConstructor(value);
|
|
1902
|
+
if (isErr2(parsedUrl)) {
|
|
1903
|
+
throw new InvalidArgumentError("Expected a valid URL for base-url.");
|
|
1904
|
+
}
|
|
1905
|
+
return parsedUrl.value.toString().replace(/\/$/u, "");
|
|
1906
|
+
}
|
|
1907
|
+
async function clearSavedAuth(dependencies) {
|
|
1908
|
+
const state = await dependencies.stateStore.load();
|
|
1909
|
+
if (!state) {
|
|
1910
|
+
return false;
|
|
1911
|
+
}
|
|
1912
|
+
await dependencies.refreshTokenStore.clear(state.account);
|
|
1913
|
+
await dependencies.stateStore.clear();
|
|
1914
|
+
return true;
|
|
1915
|
+
}
|
|
1916
|
+
async function handleSettingsEnvBaseUrl(dependencies, rawBaseUrl, options) {
|
|
1917
|
+
if (options.reset && rawBaseUrl) {
|
|
1918
|
+
throw new CliError("Pass either a base URL or --reset, not both.");
|
|
1919
|
+
}
|
|
1920
|
+
if (!options.reset && !rawBaseUrl) {
|
|
1921
|
+
throw new CliError("Provide a base URL or pass --reset.");
|
|
1922
|
+
}
|
|
1923
|
+
const settingsStore = requireSettingsStore(dependencies.settingsStore);
|
|
1924
|
+
const currentSettings = await settingsStore.load();
|
|
1925
|
+
const { baseUrl: _baseUrl, ...remainingEnvSettings } = currentSettings.env;
|
|
1926
|
+
if (options.reset) {
|
|
1927
|
+
const nextSettings2 = {
|
|
1928
|
+
...currentSettings,
|
|
1929
|
+
env: remainingEnvSettings
|
|
1930
|
+
};
|
|
1931
|
+
await settingsStore.save(nextSettings2);
|
|
1932
|
+
const authCleared2 = await clearSavedAuth(dependencies);
|
|
1933
|
+
if (options.json) {
|
|
1934
|
+
writeJsonOutput2(dependencies.io, {
|
|
1935
|
+
authCleared: authCleared2,
|
|
1936
|
+
settings: nextSettings2
|
|
1937
|
+
});
|
|
1938
|
+
return;
|
|
1939
|
+
}
|
|
1940
|
+
dependencies.io.info(
|
|
1941
|
+
authCleared2 ? 'Cleared the persisted base-url override and removed saved auth. Run "mgcl auth login" again.' : "Cleared the persisted base-url override."
|
|
1942
|
+
);
|
|
1943
|
+
return;
|
|
1944
|
+
}
|
|
1945
|
+
const nextBaseUrl = parseBaseUrl(rawBaseUrl ?? "");
|
|
1946
|
+
const nextSettings = {
|
|
1947
|
+
...currentSettings,
|
|
1948
|
+
env: {
|
|
1949
|
+
...currentSettings.env,
|
|
1950
|
+
baseUrl: nextBaseUrl
|
|
1951
|
+
}
|
|
1952
|
+
};
|
|
1953
|
+
await settingsStore.save(nextSettings);
|
|
1954
|
+
const authCleared = await clearSavedAuth(dependencies);
|
|
1955
|
+
if (options.json) {
|
|
1956
|
+
writeJsonOutput2(dependencies.io, {
|
|
1957
|
+
authCleared,
|
|
1958
|
+
settings: nextSettings
|
|
1959
|
+
});
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1962
|
+
dependencies.io.info(
|
|
1963
|
+
authCleared ? `Saved base-url override ${nextBaseUrl} and removed saved auth. Run "mgcl auth login" again.` : `Saved base-url override ${nextBaseUrl}.`
|
|
1964
|
+
);
|
|
1965
|
+
}
|
|
1966
|
+
function createSettingsCommand(dependencies) {
|
|
1967
|
+
const settingsCommand = configureCommandPresentation(
|
|
1968
|
+
new Command("settings").description("Manage persisted CLI settings.")
|
|
1969
|
+
).helpGroup("Workspace:").addHelpText(
|
|
1970
|
+
"after",
|
|
1971
|
+
`
|
|
1972
|
+
${formatExamples("Examples", [
|
|
1973
|
+
"mgcl settings env base-url http://main.localhost:1355",
|
|
1974
|
+
"mgcl settings env base-url --reset"
|
|
1975
|
+
])}`
|
|
1976
|
+
);
|
|
1977
|
+
const settingsEnvCommand = settingsCommand.command("env").description("Manage persisted environment overrides.");
|
|
1978
|
+
settingsEnvCommand.command("base-url [url]").description("Set or clear the persisted Magical API base URL override.").addOption(new Option("--reset", "Clear the persisted base URL override.")).action(async function(baseUrl) {
|
|
1979
|
+
await handleSettingsEnvBaseUrl(
|
|
1980
|
+
dependencies,
|
|
1981
|
+
baseUrl,
|
|
1982
|
+
this.optsWithGlobals()
|
|
1983
|
+
);
|
|
1984
|
+
});
|
|
1985
|
+
return settingsCommand;
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1737
1988
|
// src/state.ts
|
|
1738
|
-
import { mkdir, readFile, rm, writeFile } from "fs/promises";
|
|
1739
|
-
import
|
|
1740
|
-
import { z as
|
|
1741
|
-
var cliAccountSchema =
|
|
1742
|
-
clientId:
|
|
1743
|
-
email:
|
|
1744
|
-
userId:
|
|
1989
|
+
import { mkdir as mkdir2, readFile as readFile2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
1990
|
+
import path4 from "path";
|
|
1991
|
+
import { z as z4 } from "zod";
|
|
1992
|
+
var cliAccountSchema = z4.object({
|
|
1993
|
+
clientId: z4.string().min(1),
|
|
1994
|
+
email: z4.string().nullable(),
|
|
1995
|
+
userId: z4.string().min(1)
|
|
1745
1996
|
});
|
|
1746
|
-
var cliOrganizationSchema =
|
|
1747
|
-
id:
|
|
1748
|
-
name:
|
|
1749
|
-
primaryDomain:
|
|
1997
|
+
var cliOrganizationSchema = z4.object({
|
|
1998
|
+
id: z4.string().min(1),
|
|
1999
|
+
name: z4.string().min(1),
|
|
2000
|
+
primaryDomain: z4.string().nullable().default(null)
|
|
1750
2001
|
});
|
|
1751
|
-
var cliStateSchema =
|
|
2002
|
+
var cliStateSchema = z4.object({
|
|
1752
2003
|
account: cliAccountSchema,
|
|
1753
|
-
defaultOrgId:
|
|
1754
|
-
lastUsedOrgId:
|
|
1755
|
-
organizations:
|
|
2004
|
+
defaultOrgId: z4.string().nullable(),
|
|
2005
|
+
lastUsedOrgId: z4.string().nullable(),
|
|
2006
|
+
organizations: z4.array(cliOrganizationSchema)
|
|
1756
2007
|
});
|
|
1757
2008
|
function createFileStateStore(stateFilePath) {
|
|
1758
2009
|
return {
|
|
1759
2010
|
async clear() {
|
|
1760
|
-
await
|
|
2011
|
+
await rm2(stateFilePath, { force: true });
|
|
1761
2012
|
},
|
|
1762
2013
|
async load() {
|
|
1763
2014
|
try {
|
|
1764
|
-
const fileContents = await
|
|
2015
|
+
const fileContents = await readFile2(stateFilePath, "utf8");
|
|
1765
2016
|
const parsed = cliStateSchema.safeParse(JSON.parse(fileContents));
|
|
1766
2017
|
if (!parsed.success) {
|
|
1767
2018
|
throw new CliError("Stored CLI state is invalid.");
|
|
@@ -1778,43 +2029,43 @@ function createFileStateStore(stateFilePath) {
|
|
|
1778
2029
|
}
|
|
1779
2030
|
},
|
|
1780
2031
|
async save(state) {
|
|
1781
|
-
await
|
|
1782
|
-
await
|
|
2032
|
+
await mkdir2(path4.dirname(stateFilePath), { recursive: true });
|
|
2033
|
+
await writeFile2(stateFilePath, `${JSON.stringify(state, null, 2)}
|
|
1783
2034
|
`);
|
|
1784
2035
|
}
|
|
1785
2036
|
};
|
|
1786
2037
|
}
|
|
1787
2038
|
|
|
1788
2039
|
// src/workos-auth.ts
|
|
1789
|
-
import { z as
|
|
2040
|
+
import { z as z5 } from "zod";
|
|
1790
2041
|
var DEFAULT_DEVICE_POLL_INTERVAL_SECONDS = 5;
|
|
1791
2042
|
function buildFormHeaders() {
|
|
1792
2043
|
const headers = new Headers();
|
|
1793
2044
|
headers.set("content-type", "application/x-www-form-urlencoded");
|
|
1794
2045
|
return headers;
|
|
1795
2046
|
}
|
|
1796
|
-
var deviceAuthorizationSchema =
|
|
1797
|
-
device_code:
|
|
1798
|
-
expires_in:
|
|
1799
|
-
interval:
|
|
1800
|
-
user_code:
|
|
1801
|
-
verification_uri:
|
|
1802
|
-
verification_uri_complete:
|
|
2047
|
+
var deviceAuthorizationSchema = z5.object({
|
|
2048
|
+
device_code: z5.string().min(1),
|
|
2049
|
+
expires_in: z5.number().int().positive().optional(),
|
|
2050
|
+
interval: z5.number().int().positive().optional(),
|
|
2051
|
+
user_code: z5.string().min(1),
|
|
2052
|
+
verification_uri: z5.url(),
|
|
2053
|
+
verification_uri_complete: z5.url().optional()
|
|
1803
2054
|
});
|
|
1804
|
-
var tokenResponseSchema =
|
|
1805
|
-
access_token:
|
|
1806
|
-
expires_in:
|
|
1807
|
-
refresh_token:
|
|
1808
|
-
token_type:
|
|
2055
|
+
var tokenResponseSchema = z5.object({
|
|
2056
|
+
access_token: z5.string().min(1),
|
|
2057
|
+
expires_in: z5.number().int().positive().optional(),
|
|
2058
|
+
refresh_token: z5.string().min(1),
|
|
2059
|
+
token_type: z5.string().optional()
|
|
1809
2060
|
});
|
|
1810
|
-
var tokenErrorSchema =
|
|
1811
|
-
error:
|
|
1812
|
-
error_description:
|
|
2061
|
+
var tokenErrorSchema = z5.object({
|
|
2062
|
+
error: z5.string().min(1),
|
|
2063
|
+
error_description: z5.string().optional()
|
|
1813
2064
|
});
|
|
1814
|
-
var accessTokenClaimsSchema =
|
|
1815
|
-
org_id:
|
|
1816
|
-
sid:
|
|
1817
|
-
sub:
|
|
2065
|
+
var accessTokenClaimsSchema = z5.object({
|
|
2066
|
+
org_id: z5.string().min(1).optional(),
|
|
2067
|
+
sid: z5.string().min(1).optional(),
|
|
2068
|
+
sub: z5.string().min(1)
|
|
1818
2069
|
});
|
|
1819
2070
|
function createWorkosAuthClient({
|
|
1820
2071
|
fetchFn = fetch,
|
|
@@ -1971,7 +2222,7 @@ function parseCommandOptionValue(rawValue, optionSpec) {
|
|
|
1971
2222
|
case "number": {
|
|
1972
2223
|
const parsedNumber = Number(rawValue);
|
|
1973
2224
|
if (Number.isNaN(parsedNumber)) {
|
|
1974
|
-
throw new
|
|
2225
|
+
throw new InvalidArgumentError2(
|
|
1975
2226
|
`Expected a number for --${optionSpec.flagName}.`
|
|
1976
2227
|
);
|
|
1977
2228
|
}
|
|
@@ -1984,7 +2235,7 @@ function parseCommandOptionValue(rawValue, optionSpec) {
|
|
|
1984
2235
|
try {
|
|
1985
2236
|
return JSON.parse(rawValue);
|
|
1986
2237
|
} catch {
|
|
1987
|
-
throw new
|
|
2238
|
+
throw new InvalidArgumentError2(
|
|
1988
2239
|
`Expected valid JSON for --${optionSpec.flagName}.`
|
|
1989
2240
|
);
|
|
1990
2241
|
}
|
|
@@ -2038,7 +2289,7 @@ function requireLoggedInState(state) {
|
|
|
2038
2289
|
}
|
|
2039
2290
|
return state;
|
|
2040
2291
|
}
|
|
2041
|
-
function
|
|
2292
|
+
function writeJsonOutput3(io, value) {
|
|
2042
2293
|
io.info(JSON.stringify(value, null, 2));
|
|
2043
2294
|
}
|
|
2044
2295
|
function collectOperationVariables(operationSpec, options) {
|
|
@@ -2094,69 +2345,6 @@ async function withOrgScopedAccessToken({
|
|
|
2094
2345
|
accessToken: tokenResponse.access_token
|
|
2095
2346
|
};
|
|
2096
2347
|
}
|
|
2097
|
-
async function handleAuthLogin(dependencies, options) {
|
|
2098
|
-
const clientId = requireWorkosClientId(dependencies.runtimeConfig);
|
|
2099
|
-
const deviceAuthorization = await dependencies.authClient.startDeviceAuthorization({ clientId });
|
|
2100
|
-
const verificationUrl = deviceAuthorization.verification_uri_complete ?? deviceAuthorization.verification_uri;
|
|
2101
|
-
const promptWriter = options.json ? dependencies.io.error : dependencies.io.info;
|
|
2102
|
-
promptWriter(
|
|
2103
|
-
formatAuthLoginPrompt({
|
|
2104
|
-
userCode: deviceAuthorization.user_code,
|
|
2105
|
-
verificationUrl
|
|
2106
|
-
})
|
|
2107
|
-
);
|
|
2108
|
-
await dependencies.openExternalUrl(verificationUrl).catch(() => {
|
|
2109
|
-
promptWriter(formatBrowserOpenFallback());
|
|
2110
|
-
});
|
|
2111
|
-
const tokenResponse = await dependencies.authClient.pollForDeviceTokens({
|
|
2112
|
-
clientId,
|
|
2113
|
-
deviceCode: deviceAuthorization.device_code,
|
|
2114
|
-
...deviceAuthorization.expires_in ? { expiresInSeconds: deviceAuthorization.expires_in } : {},
|
|
2115
|
-
...deviceAuthorization.interval ? { intervalSeconds: deviceAuthorization.interval } : {}
|
|
2116
|
-
});
|
|
2117
|
-
const accessTokenClaims = dependencies.authClient.decodeAccessTokenClaims(
|
|
2118
|
-
tokenResponse.access_token
|
|
2119
|
-
);
|
|
2120
|
-
const [user, organizations] = await Promise.all([
|
|
2121
|
-
dependencies.apiClient.fetchUser({
|
|
2122
|
-
accessToken: tokenResponse.access_token,
|
|
2123
|
-
userId: accessTokenClaims.sub
|
|
2124
|
-
}),
|
|
2125
|
-
dependencies.apiClient.fetchOrganizations({
|
|
2126
|
-
accessToken: tokenResponse.access_token
|
|
2127
|
-
})
|
|
2128
|
-
]);
|
|
2129
|
-
const defaultOrgId = accessTokenClaims.org_id ?? organizations[0]?.id ?? null;
|
|
2130
|
-
const nextState = {
|
|
2131
|
-
account: {
|
|
2132
|
-
clientId,
|
|
2133
|
-
email: user.email,
|
|
2134
|
-
userId: user.id
|
|
2135
|
-
},
|
|
2136
|
-
defaultOrgId,
|
|
2137
|
-
lastUsedOrgId: defaultOrgId,
|
|
2138
|
-
organizations
|
|
2139
|
-
};
|
|
2140
|
-
await Promise.all([
|
|
2141
|
-
dependencies.refreshTokenStore.save(
|
|
2142
|
-
nextState.account,
|
|
2143
|
-
tokenResponse.refresh_token
|
|
2144
|
-
),
|
|
2145
|
-
dependencies.stateStore.save(nextState)
|
|
2146
|
-
]);
|
|
2147
|
-
const defaultOrganization = organizations.find((organization) => organization.id === defaultOrgId) ?? null;
|
|
2148
|
-
if (options.json) {
|
|
2149
|
-
writeJsonOutput(dependencies.io, nextState);
|
|
2150
|
-
return;
|
|
2151
|
-
}
|
|
2152
|
-
dependencies.io.info(
|
|
2153
|
-
formatAuthLoginSuccess({
|
|
2154
|
-
account: nextState.account,
|
|
2155
|
-
defaultOrganization,
|
|
2156
|
-
organizationCount: organizations.length
|
|
2157
|
-
})
|
|
2158
|
-
);
|
|
2159
|
-
}
|
|
2160
2348
|
async function handleAuthLogout(dependencies, options) {
|
|
2161
2349
|
const state = await dependencies.stateStore.load();
|
|
2162
2350
|
if (state) {
|
|
@@ -2164,7 +2352,7 @@ async function handleAuthLogout(dependencies, options) {
|
|
|
2164
2352
|
}
|
|
2165
2353
|
await dependencies.stateStore.clear();
|
|
2166
2354
|
if (options.json) {
|
|
2167
|
-
|
|
2355
|
+
writeJsonOutput3(dependencies.io, { loggedOut: true });
|
|
2168
2356
|
return;
|
|
2169
2357
|
}
|
|
2170
2358
|
dependencies.io.info(formatLogoutSuccess());
|
|
@@ -2172,7 +2360,7 @@ async function handleAuthLogout(dependencies, options) {
|
|
|
2172
2360
|
async function handleOrgList(dependencies, options) {
|
|
2173
2361
|
const state = requireLoggedInState(await dependencies.stateStore.load());
|
|
2174
2362
|
if (options.json) {
|
|
2175
|
-
|
|
2363
|
+
writeJsonOutput3(dependencies.io, state.organizations);
|
|
2176
2364
|
return;
|
|
2177
2365
|
}
|
|
2178
2366
|
dependencies.io.info(
|
|
@@ -2196,7 +2384,7 @@ async function handleOrgUse(dependencies, organizationSelector, options) {
|
|
|
2196
2384
|
};
|
|
2197
2385
|
await dependencies.stateStore.save(nextState);
|
|
2198
2386
|
if (options.json) {
|
|
2199
|
-
|
|
2387
|
+
writeJsonOutput3(dependencies.io, {
|
|
2200
2388
|
defaultOrgId: organization.id,
|
|
2201
2389
|
organization
|
|
2202
2390
|
});
|
|
@@ -2211,7 +2399,7 @@ async function handleSelfUpdate(dependencies, options) {
|
|
|
2211
2399
|
}
|
|
2212
2400
|
const updateResult = await selfUpdateCli();
|
|
2213
2401
|
if (options.json) {
|
|
2214
|
-
|
|
2402
|
+
writeJsonOutput3(dependencies.io, {
|
|
2215
2403
|
installPrefix: updateResult.installPrefix,
|
|
2216
2404
|
packageSpecifier: updateResult.packageSpecifier,
|
|
2217
2405
|
registryUrl: updateResult.registryUrl,
|
|
@@ -2246,7 +2434,7 @@ async function handleOperationCommand(dependencies, operationSpec, commandOption
|
|
|
2246
2434
|
lastUsedOrgId: organization.id
|
|
2247
2435
|
});
|
|
2248
2436
|
if (commandOptions.json) {
|
|
2249
|
-
|
|
2437
|
+
writeJsonOutput3(dependencies.io, result);
|
|
2250
2438
|
return;
|
|
2251
2439
|
}
|
|
2252
2440
|
dependencies.io.info(formatHumanReadableOutput(result));
|
|
@@ -2294,7 +2482,7 @@ function addRegistryOperationCommand({
|
|
|
2294
2482
|
}
|
|
2295
2483
|
function configureOperationalCommand(command, dependencies, operationSpec) {
|
|
2296
2484
|
command.description(operationSpec.cli.description).addOption(
|
|
2297
|
-
new
|
|
2485
|
+
new Option2(
|
|
2298
2486
|
"--org <org>",
|
|
2299
2487
|
"Organization ID or exact organization name to use."
|
|
2300
2488
|
).helpGroup("Shared options:")
|
|
@@ -2309,7 +2497,7 @@ ${formatExamples(
|
|
|
2309
2497
|
for (const optionSpec of operationSpec.cli.options) {
|
|
2310
2498
|
const optionFlags = optionSpec.valueType === "boolean" ? `--${optionSpec.flagName}` : `--${optionSpec.flagName} <value>`;
|
|
2311
2499
|
const optionDescription = optionSpec.valueHint ? `${optionSpec.description} (${optionSpec.valueHint})` : optionSpec.description;
|
|
2312
|
-
const nextOption = new
|
|
2500
|
+
const nextOption = new Option2(optionFlags, optionDescription).helpGroup(
|
|
2313
2501
|
operationSpec.kind === "query" ? "Query options:" : "Mutation options:"
|
|
2314
2502
|
);
|
|
2315
2503
|
if (optionSpec.valueType === "boolean") {
|
|
@@ -2347,13 +2535,17 @@ function createConsoleIo() {
|
|
|
2347
2535
|
}
|
|
2348
2536
|
function createDefaultDependencies() {
|
|
2349
2537
|
const runtimeConfig = getRuntimeConfig();
|
|
2538
|
+
const settingsStore = createFileSettingsStore(runtimeConfig.stateFilePath);
|
|
2350
2539
|
const selfUpdateOptions = {
|
|
2351
2540
|
...runtimeConfig.cliDistTag ? { distTag: runtimeConfig.cliDistTag } : {},
|
|
2352
2541
|
...runtimeConfig.npmRegistryUrl ? { registryUrl: runtimeConfig.npmRegistryUrl } : {}
|
|
2353
2542
|
};
|
|
2354
2543
|
return {
|
|
2355
2544
|
apiClient: createMagicalApiClient({
|
|
2356
|
-
apiBaseUrl:
|
|
2545
|
+
apiBaseUrl: async () => resolveConfiguredApiBaseUrl({
|
|
2546
|
+
defaultApiBaseUrl: runtimeConfig.magicalApiUrl,
|
|
2547
|
+
settings: await settingsStore.load()
|
|
2548
|
+
})
|
|
2357
2549
|
}),
|
|
2358
2550
|
authClient: createWorkosAuthClient({
|
|
2359
2551
|
workosApiUrl: runtimeConfig.workosApiUrl
|
|
@@ -2364,15 +2556,16 @@ function createDefaultDependencies() {
|
|
|
2364
2556
|
runtimeConfig.keychainServiceName
|
|
2365
2557
|
),
|
|
2366
2558
|
runtimeConfig,
|
|
2559
|
+
settingsStore,
|
|
2367
2560
|
selfUpdateCli: async () => selfUpdateInstalledCli(selfUpdateOptions),
|
|
2368
2561
|
stateStore: createFileStateStore(runtimeConfig.stateFilePath)
|
|
2369
2562
|
};
|
|
2370
2563
|
}
|
|
2371
2564
|
function buildProgram(dependencies) {
|
|
2372
2565
|
const program2 = configureCommandPresentation(
|
|
2373
|
-
new
|
|
2374
|
-
).addOption(new
|
|
2375
|
-
new
|
|
2566
|
+
new Command2().name("mgcl").description("Run Magical operations from the command line.")
|
|
2567
|
+
).addOption(new Option2("--json", "Render JSON output.")).addOption(
|
|
2568
|
+
new Option2(
|
|
2376
2569
|
"--update",
|
|
2377
2570
|
"Update mgcl to the latest published npm release."
|
|
2378
2571
|
)
|
|
@@ -2398,14 +2591,11 @@ ${formatOutputModesNote()}`
|
|
|
2398
2591
|
this.outputHelp();
|
|
2399
2592
|
});
|
|
2400
2593
|
const authCommand = configureCommandPresentation(
|
|
2401
|
-
new
|
|
2594
|
+
new Command2("auth").description("Manage CLI authentication.")
|
|
2402
2595
|
).helpGroup("Workspace:").addHelpText(
|
|
2403
2596
|
"after",
|
|
2404
2597
|
`
|
|
2405
|
-
${formatExamples("Examples", [
|
|
2406
|
-
"mgcl auth login",
|
|
2407
|
-
"mgcl auth logout"
|
|
2408
|
-
])}`
|
|
2598
|
+
${formatExamples("Examples", ["mgcl auth login", "mgcl auth logout"])}`
|
|
2409
2599
|
);
|
|
2410
2600
|
authCommand.command("login").description("Authenticate with Magical and load organization memberships.").action(async function() {
|
|
2411
2601
|
await handleAuthLogin(dependencies, this.optsWithGlobals());
|
|
@@ -2414,8 +2604,9 @@ ${formatExamples("Examples", [
|
|
|
2414
2604
|
await handleAuthLogout(dependencies, this.optsWithGlobals());
|
|
2415
2605
|
});
|
|
2416
2606
|
program2.addCommand(authCommand);
|
|
2607
|
+
program2.addCommand(createSettingsCommand(dependencies));
|
|
2417
2608
|
const orgCommand = configureCommandPresentation(
|
|
2418
|
-
new
|
|
2609
|
+
new Command2("org").description("Manage organization selection.")
|
|
2419
2610
|
).helpGroup("Workspace:").addHelpText(
|
|
2420
2611
|
"after",
|
|
2421
2612
|
`
|
|
@@ -2436,7 +2627,7 @@ ${formatExamples("Examples", [
|
|
|
2436
2627
|
});
|
|
2437
2628
|
program2.addCommand(orgCommand);
|
|
2438
2629
|
const updateCommand = configureCommandPresentation(
|
|
2439
|
-
new
|
|
2630
|
+
new Command2("update").description(
|
|
2440
2631
|
"Update mgcl to the latest published npm release."
|
|
2441
2632
|
)
|
|
2442
2633
|
).helpGroup("Workspace:").addHelpText(
|