@nimblebrain/mpak 0.0.1-beta.1
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/.env.example +13 -0
- package/CLAUDE.md +117 -0
- package/LICENSE +201 -0
- package/README.md +206 -0
- package/dist/commands/packages/pull.d.ts +11 -0
- package/dist/commands/packages/pull.d.ts.map +1 -0
- package/dist/commands/packages/pull.js +72 -0
- package/dist/commands/packages/pull.js.map +1 -0
- package/dist/commands/packages/search.d.ts +12 -0
- package/dist/commands/packages/search.d.ts.map +1 -0
- package/dist/commands/packages/search.js +63 -0
- package/dist/commands/packages/search.js.map +1 -0
- package/dist/commands/packages/show.d.ts +8 -0
- package/dist/commands/packages/show.d.ts.map +1 -0
- package/dist/commands/packages/show.js +121 -0
- package/dist/commands/packages/show.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api/registry-client.d.ts +63 -0
- package/dist/lib/api/registry-client.d.ts.map +1 -0
- package/dist/lib/api/registry-client.js +167 -0
- package/dist/lib/api/registry-client.js.map +1 -0
- package/dist/program.d.ts +8 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +69 -0
- package/dist/program.js.map +1 -0
- package/dist/utils/config-manager.d.ts +23 -0
- package/dist/utils/config-manager.d.ts.map +1 -0
- package/dist/utils/config-manager.js +65 -0
- package/dist/utils/config-manager.js.map +1 -0
- package/dist/utils/errors.d.ts +12 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +27 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/version.d.ts +5 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +19 -0
- package/dist/utils/version.js.map +1 -0
- package/eslint.config.js +63 -0
- package/package.json +48 -0
- package/src/commands/packages/pull.ts +96 -0
- package/src/commands/packages/search.ts +83 -0
- package/src/commands/packages/show.ts +138 -0
- package/src/index.ts +15 -0
- package/src/lib/api/registry-client.ts +223 -0
- package/src/lib/api/schema.d.ts +548 -0
- package/src/program.test.ts +24 -0
- package/src/program.ts +76 -0
- package/src/utils/config-manager.test.ts +60 -0
- package/src/utils/config-manager.ts +81 -0
- package/src/utils/errors.test.ts +25 -0
- package/src/utils/errors.ts +33 -0
- package/src/utils/version.test.ts +16 -0
- package/src/utils/version.ts +18 -0
- package/tsconfig.json +25 -0
- package/vitest.config.ts +13 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { ConfigManager } from './config-manager.js';
|
|
3
|
+
import { existsSync, rmSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { homedir } from 'os';
|
|
6
|
+
|
|
7
|
+
describe('ConfigManager', () => {
|
|
8
|
+
const testConfigDir = join(homedir(), '.mpak');
|
|
9
|
+
const testConfigFile = join(testConfigDir, 'config.json');
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
// Clean up test config before each test
|
|
13
|
+
if (existsSync(testConfigFile)) {
|
|
14
|
+
rmSync(testConfigFile, { force: true });
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
// Clean up test config after each test
|
|
20
|
+
if (existsSync(testConfigFile)) {
|
|
21
|
+
rmSync(testConfigFile, { force: true });
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('loadConfig', () => {
|
|
26
|
+
it('should create a new config if none exists', () => {
|
|
27
|
+
const manager = new ConfigManager();
|
|
28
|
+
const config = manager.loadConfig();
|
|
29
|
+
|
|
30
|
+
expect(config).toBeDefined();
|
|
31
|
+
expect(config.version).toBe('1.0.0');
|
|
32
|
+
expect(config.lastUpdated).toBeTruthy();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should set registryUrl in config', () => {
|
|
36
|
+
const manager = new ConfigManager();
|
|
37
|
+
manager.setRegistryUrl('http://test.example.com');
|
|
38
|
+
|
|
39
|
+
// Get the config to verify it's set
|
|
40
|
+
expect(manager.getRegistryUrl()).toBe('http://test.example.com');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('getRegistryUrl', () => {
|
|
45
|
+
it('should return default registry URL', () => {
|
|
46
|
+
const manager = new ConfigManager();
|
|
47
|
+
const url = manager.getRegistryUrl();
|
|
48
|
+
|
|
49
|
+
expect(url).toBe('https://api.mpak.dev');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should return configured registry URL', () => {
|
|
53
|
+
const manager = new ConfigManager();
|
|
54
|
+
manager.setRegistryUrl('http://custom.example.com');
|
|
55
|
+
|
|
56
|
+
expect(manager.getRegistryUrl()).toBe('http://custom.example.com');
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Configuration structure
|
|
7
|
+
*/
|
|
8
|
+
export interface MpakConfig {
|
|
9
|
+
version: string;
|
|
10
|
+
lastUpdated: string;
|
|
11
|
+
registryUrl?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Configuration manager for CLI settings in ~/.mpak/config.json
|
|
16
|
+
*/
|
|
17
|
+
export class ConfigManager {
|
|
18
|
+
private configDir: string;
|
|
19
|
+
private configFile: string;
|
|
20
|
+
private config: MpakConfig | null = null;
|
|
21
|
+
|
|
22
|
+
constructor() {
|
|
23
|
+
this.configDir = join(homedir(), '.mpak');
|
|
24
|
+
this.configFile = join(this.configDir, 'config.json');
|
|
25
|
+
this.ensureConfigDir();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private ensureConfigDir(): void {
|
|
29
|
+
if (!existsSync(this.configDir)) {
|
|
30
|
+
mkdirSync(this.configDir, { recursive: true, mode: 0o700 });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
loadConfig(): MpakConfig {
|
|
35
|
+
if (this.config) {
|
|
36
|
+
return this.config;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!existsSync(this.configFile)) {
|
|
40
|
+
this.config = {
|
|
41
|
+
version: '1.0.0',
|
|
42
|
+
lastUpdated: new Date().toISOString(),
|
|
43
|
+
};
|
|
44
|
+
this.saveConfig();
|
|
45
|
+
return this.config;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const configJson = readFileSync(this.configFile, 'utf8');
|
|
50
|
+
this.config = JSON.parse(configJson) as MpakConfig;
|
|
51
|
+
return this.config;
|
|
52
|
+
} catch {
|
|
53
|
+
this.config = {
|
|
54
|
+
version: '1.0.0',
|
|
55
|
+
lastUpdated: new Date().toISOString(),
|
|
56
|
+
};
|
|
57
|
+
this.saveConfig();
|
|
58
|
+
return this.config;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private saveConfig(): void {
|
|
63
|
+
if (!this.config) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.config.lastUpdated = new Date().toISOString();
|
|
67
|
+
const configJson = JSON.stringify(this.config, null, 2);
|
|
68
|
+
writeFileSync(this.configFile, configJson, { mode: 0o600 });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setRegistryUrl(url: string): void {
|
|
72
|
+
const config = this.loadConfig();
|
|
73
|
+
config.registryUrl = url;
|
|
74
|
+
this.saveConfig();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getRegistryUrl(): string {
|
|
78
|
+
const config = this.loadConfig();
|
|
79
|
+
return config.registryUrl || process.env.MPAK_REGISTRY_URL || 'https://api.mpak.dev';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { CLIError } from './errors.js';
|
|
3
|
+
|
|
4
|
+
describe('CLIError', () => {
|
|
5
|
+
it('should create error with message', () => {
|
|
6
|
+
const error = new CLIError('Test error');
|
|
7
|
+
expect(error.message).toBe('Test error');
|
|
8
|
+
expect(error.name).toBe('CLIError');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should have default exit code of 1', () => {
|
|
12
|
+
const error = new CLIError('Test error');
|
|
13
|
+
expect(error.exitCode).toBe(1);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should allow custom exit code', () => {
|
|
17
|
+
const error = new CLIError('Test error', 2);
|
|
18
|
+
expect(error.exitCode).toBe(2);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should be instance of Error', () => {
|
|
22
|
+
const error = new CLIError('Test error');
|
|
23
|
+
expect(error).toBeInstanceOf(Error);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error class for CLI errors
|
|
3
|
+
*/
|
|
4
|
+
export class CLIError extends Error {
|
|
5
|
+
public readonly exitCode: number;
|
|
6
|
+
|
|
7
|
+
constructor(
|
|
8
|
+
message: string,
|
|
9
|
+
exitCode: number = 1
|
|
10
|
+
) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'CLIError';
|
|
13
|
+
this.exitCode = exitCode;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Handles errors gracefully and exits with appropriate code
|
|
19
|
+
*/
|
|
20
|
+
export function handleError(error: unknown): never {
|
|
21
|
+
if (error instanceof CLIError) {
|
|
22
|
+
console.error(`Error: ${error.message}`);
|
|
23
|
+
process.exit(error.exitCode);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (error instanceof Error) {
|
|
27
|
+
console.error(`Error: ${error.message}`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
console.error('An unexpected error occurred');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { getVersion } from './version.js';
|
|
3
|
+
|
|
4
|
+
describe('getVersion', () => {
|
|
5
|
+
it('should return a valid version string', () => {
|
|
6
|
+
const version = getVersion();
|
|
7
|
+
expect(version).toBeTruthy();
|
|
8
|
+
expect(typeof version).toBe('string');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should match semver format or be "unknown"', () => {
|
|
12
|
+
const version = getVersion();
|
|
13
|
+
const semverRegex = /^\d+\.\d+\.\d+/;
|
|
14
|
+
expect(version === 'unknown' || semverRegex.test(version)).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Gets the current version from package.json
|
|
7
|
+
*/
|
|
8
|
+
export function getVersion(): string {
|
|
9
|
+
try {
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = dirname(__filename);
|
|
12
|
+
const packageJsonPath = join(__dirname, '../../package.json');
|
|
13
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
14
|
+
return packageJson.version;
|
|
15
|
+
} catch (_error) {
|
|
16
|
+
return 'unknown';
|
|
17
|
+
}
|
|
18
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"resolveJsonModule": true,
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"outDir": "./dist",
|
|
10
|
+
"rootDir": "./src",
|
|
11
|
+
"strict": true,
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"declaration": true,
|
|
16
|
+
"declarationMap": true,
|
|
17
|
+
"sourceMap": true,
|
|
18
|
+
"noUnusedLocals": true,
|
|
19
|
+
"noUnusedParameters": true,
|
|
20
|
+
"noImplicitReturns": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true
|
|
22
|
+
},
|
|
23
|
+
"include": ["src/**/*"],
|
|
24
|
+
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
|
25
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: 'node',
|
|
7
|
+
coverage: {
|
|
8
|
+
provider: 'v8',
|
|
9
|
+
reporter: ['text', 'json', 'html'],
|
|
10
|
+
exclude: ['dist', 'node_modules', '**/*.test.ts', '**/*.config.ts'],
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
});
|