Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 27 additions & 55 deletions packages/cli/src/commands/config.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,38 @@
import { ConfigManager } from "../utils/config-manager.js";
import type { PackageConfig } from "../utils/config-manager.js";

// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface ConfigSetOptions {}
import type { PackageConfig } from '@nimblebrain/mpak-sdk';
import { mpak } from '../utils/config.js';

export interface ConfigGetOptions {
json?: boolean;
}

// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface ConfigClearOptions {}

/**
* Mask sensitive values for display (show first 4 chars, rest as *)
*/
function maskValue(value: string): string {
if (value.length <= 4) {
return "*".repeat(value.length);
return '*'.repeat(value.length);
}
return value.substring(0, 4) + "*".repeat(value.length - 4);
return value.substring(0, 4) + '*'.repeat(value.length - 4);
}

/**
* Set config value(s) for a package
* @example mpak config set @scope/name api_key=xxx
* @example mpak config set @scope/name api_key=xxx other_key=yyy
*/
export async function handleConfigSet(
packageName: string,
keyValuePairs: string[],
_options: ConfigSetOptions = {},
): Promise<void> {
export async function handleConfigSet(packageName: string, keyValuePairs: string[]): Promise<void> {
if (keyValuePairs.length === 0) {
process.stderr.write(
"Error: At least one key=value pair is required\n",
);
process.stderr.write(
"Usage: mpak config set <package> <key>=<value> [<key>=<value>...]\n",
);
process.stderr.write('Error: At least one key=value pair is required\n');
process.stderr.write('Usage: mpak config set <package> <key>=<value> [<key>=<value>...]\n');
process.exit(1);
}

const configManager = new ConfigManager();
let setCount = 0;

for (const pair of keyValuePairs) {
const eqIndex = pair.indexOf("=");
const eqIndex = pair.indexOf('=');
if (eqIndex === -1) {
process.stderr.write(
`Error: Invalid format "${pair}". Expected key=value\n`,
);
process.stderr.write(`Error: Invalid format "${pair}". Expected key=value\n`);
process.exit(1);
}

Expand All @@ -61,7 +44,7 @@ export async function handleConfigSet(
process.exit(1);
}

configManager.setPackageConfigValue(packageName, key, value);
mpak.configManager.setPackageConfigValue(packageName, key, value);
setCount++;
}

Expand All @@ -77,19 +60,18 @@ export async function handleConfigGet(
packageName: string,
options: ConfigGetOptions = {},
): Promise<void> {
const configManager = new ConfigManager();
const config = configManager.getPackageConfig(packageName);
const config = mpak.configManager.getPackageConfig(packageName);
const isOutputJson = !!options?.json;

// If no config or config is {}
if (!config || Object.keys(config).length === 0) {
if (options.json) {
if (isOutputJson) {
console.log(JSON.stringify({}, null, 2));
} else {
console.log(`No config stored for ${packageName}`);
}
return;
}

if (options.json) {
} else if (isOutputJson) {
// Mask values in JSON output too
const masked: PackageConfig = {};
for (const [key, value] of Object.entries(config)) {
Expand All @@ -108,31 +90,27 @@ export async function handleConfigGet(
* List all packages with stored config
* @example mpak config list
*/
export async function handleConfigList(
options: ConfigGetOptions = {},
): Promise<void> {
const configManager = new ConfigManager();
const packages = configManager.listPackagesWithConfig();
export async function handleConfigList(options: ConfigGetOptions = {}): Promise<void> {
const packages = mpak.configManager.getPackageNames();
const isOutputJson = !!options?.json;

if (packages.length === 0) {
if (options.json) {
if (isOutputJson) {
console.log(JSON.stringify([], null, 2));
} else {
console.log("No packages have stored config");
console.log('No packages have stored config');
}
return;
}

if (options.json) {
if (isOutputJson) {
console.log(JSON.stringify(packages, null, 2));
} else {
console.log("Packages with stored config:");
console.log('Packages with stored config:');
for (const pkg of packages) {
const config = configManager.getPackageConfig(pkg);
const config = mpak.configManager.getPackageConfig(pkg);
const keyCount = config ? Object.keys(config).length : 0;
console.log(
` ${pkg} (${keyCount} value${keyCount === 1 ? "" : "s"})`,
);
console.log(`${pkg} (${keyCount} value${keyCount === 1 ? '' : 's'})`);
}
}
}
Expand All @@ -142,24 +120,18 @@ export async function handleConfigList(
* @example mpak config clear @scope/name # clears all
* @example mpak config clear @scope/name api_key # clears specific key
*/
export async function handleConfigClear(
packageName: string,
key?: string,
_options: ConfigClearOptions = {},
): Promise<void> {
const configManager = new ConfigManager();

export async function handleConfigClear(packageName: string, key?: string): Promise<void> {
if (key) {
// Clear specific key
const cleared = configManager.clearPackageConfigValue(packageName, key);
const cleared = mpak.configManager.clearPackageConfigValue(packageName, key);
if (cleared) {
console.log(`Cleared ${key} for ${packageName}`);
} else {
console.log(`No value found for ${key} in ${packageName}`);
}
} else {
// Clear all config for package
const cleared = configManager.clearPackageConfig(packageName);
const cleared = mpak.configManager.clearPackageConfig(packageName);
if (cleared) {
console.log(`Cleared all config for ${packageName}`);
} else {
Expand Down
123 changes: 0 additions & 123 deletions packages/cli/src/commands/packages/outdated.test.ts

This file was deleted.

28 changes: 14 additions & 14 deletions packages/cli/src/commands/packages/outdated.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { isSemverEqual, listCachedBundles } from "../../utils/cache.js";
import { createClient } from "../../utils/client.js";
import { table } from "../../utils/format.js";
import { mpak } from '../../utils/config.js';
import { logger, table } from '../../utils/format.js';

export interface OutdatedEntry {
name: string;
Expand All @@ -18,26 +17,27 @@ export interface OutdatedOptions {
* that have a newer version available.
*/
export async function getOutdatedBundles(): Promise<OutdatedEntry[]> {
const cached = listCachedBundles();
const cached = mpak.bundleCache.listCachedBundles();
if (cached.length === 0) return [];

const client = createClient();
const results: OutdatedEntry[] = [];

await Promise.all(
cached.map(async (bundle) => {
try {
const detail = await client.getBundle(bundle.name);
if (!isSemverEqual(detail.latest_version, bundle.version)) {
const latest = await mpak.bundleCache.checkForUpdate(bundle.name, { force: true });
if (latest) {
results.push({
name: bundle.name,
current: bundle.version,
latest: detail.latest_version,
latest,
pulledAt: bundle.pulledAt,
});
}
} catch {
process.stderr.write(`=> Warning: could not check ${bundle.name} (may have been removed from registry)\n`);
process.stderr.write(
`=> Warning: could not check ${bundle.name} (may have been removed from registry)\n`,
);
}
}),
);
Expand All @@ -46,7 +46,7 @@ export async function getOutdatedBundles(): Promise<OutdatedEntry[]> {
}

export async function handleOutdated(options: OutdatedOptions = {}): Promise<void> {
process.stderr.write("=> Checking for updates...\n");
process.stderr.write('=> Checking for updates...\n');

const outdated = await getOutdatedBundles();

Expand All @@ -56,15 +56,15 @@ export async function handleOutdated(options: OutdatedOptions = {}): Promise<voi
}

if (outdated.length === 0) {
console.log("All cached bundles are up to date.");
logger.info('All cached bundles are up to date.');
return;
}

console.log(
logger.info(
table(
["Bundle", "Current", "Latest", "Pulled"],
['Bundle', 'Current', 'Latest', 'Pulled'],
outdated.map((e) => [e.name, e.current, e.latest, e.pulledAt]),
),
);
console.log(`\n${outdated.length} bundle(s) can be updated. Run 'mpak update' to update all.`);
logger.info(`\n${outdated.length} bundle(s) can be updated. Run 'mpak update' to update all.`);
}
Loading
Loading