@nimblebrain/mpak 0.0.1 → 0.0.2
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/.claude/settings.local.json +3 -1
- package/CLAUDE.md +73 -34
- package/README.md +222 -57
- package/dist/commands/search.d.ts +12 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +144 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/skills/index.d.ts +8 -0
- package/dist/commands/skills/index.d.ts.map +1 -0
- package/dist/commands/skills/index.js +8 -0
- package/dist/commands/skills/index.js.map +1 -0
- package/dist/commands/skills/install.d.ts +9 -0
- package/dist/commands/skills/install.d.ts.map +1 -0
- package/dist/commands/skills/install.js +110 -0
- package/dist/commands/skills/install.js.map +1 -0
- package/dist/commands/skills/list.d.ts +8 -0
- package/dist/commands/skills/list.d.ts.map +1 -0
- package/dist/commands/skills/list.js +89 -0
- package/dist/commands/skills/list.js.map +1 -0
- package/dist/commands/skills/pack.d.ts +22 -0
- package/dist/commands/skills/pack.d.ts.map +1 -0
- package/dist/commands/skills/pack.js +116 -0
- package/dist/commands/skills/pack.js.map +1 -0
- package/dist/commands/skills/pull.d.ts +9 -0
- package/dist/commands/skills/pull.d.ts.map +1 -0
- package/dist/commands/skills/pull.js +68 -0
- package/dist/commands/skills/pull.js.map +1 -0
- package/dist/commands/skills/search.d.ts +14 -0
- package/dist/commands/skills/search.d.ts.map +1 -0
- package/dist/commands/skills/search.js +53 -0
- package/dist/commands/skills/search.js.map +1 -0
- package/dist/commands/skills/show.d.ts +8 -0
- package/dist/commands/skills/show.d.ts.map +1 -0
- package/dist/commands/skills/show.js +64 -0
- package/dist/commands/skills/show.js.map +1 -0
- package/dist/commands/skills/validate.d.ts +25 -0
- package/dist/commands/skills/validate.d.ts.map +1 -0
- package/dist/commands/skills/validate.js +191 -0
- package/dist/commands/skills/validate.js.map +1 -0
- package/dist/lib/api/skills-client.d.ts +30 -0
- package/dist/lib/api/skills-client.d.ts.map +1 -0
- package/dist/lib/api/skills-client.js +110 -0
- package/dist/lib/api/skills-client.js.map +1 -0
- package/dist/program.d.ts +5 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +98 -33
- package/dist/program.js.map +1 -1
- package/dist/schemas/generated/api-responses.d.ts +541 -0
- package/dist/schemas/generated/api-responses.d.ts.map +1 -0
- package/dist/schemas/generated/api-responses.js +313 -0
- package/dist/schemas/generated/api-responses.js.map +1 -0
- package/dist/schemas/generated/auth.d.ts +18 -0
- package/dist/schemas/generated/auth.d.ts.map +1 -0
- package/dist/schemas/generated/auth.js +18 -0
- package/dist/schemas/generated/auth.js.map +1 -0
- package/dist/schemas/generated/index.d.ts +5 -0
- package/dist/schemas/generated/index.d.ts.map +1 -0
- package/dist/schemas/generated/index.js +6 -0
- package/dist/schemas/generated/index.js.map +1 -0
- package/dist/schemas/generated/package.d.ts +43 -0
- package/dist/schemas/generated/package.d.ts.map +1 -0
- package/dist/schemas/generated/package.js +20 -0
- package/dist/schemas/generated/package.js.map +1 -0
- package/dist/schemas/generated/skill.d.ts +381 -0
- package/dist/schemas/generated/skill.d.ts.map +1 -0
- package/dist/schemas/generated/skill.js +216 -0
- package/dist/schemas/generated/skill.js.map +1 -0
- package/dist/utils/config-manager.d.ts +13 -1
- package/dist/utils/config-manager.d.ts.map +1 -1
- package/dist/utils/config-manager.js +76 -11
- package/dist/utils/config-manager.js.map +1 -1
- package/package.json +6 -2
- package/src/commands/search.ts +191 -0
- package/src/commands/skills/index.ts +7 -0
- package/src/commands/skills/install.ts +129 -0
- package/src/commands/skills/list.ts +116 -0
- package/src/commands/skills/pack.test.ts +260 -0
- package/src/commands/skills/pack.ts +145 -0
- package/src/commands/skills/pull.ts +88 -0
- package/src/commands/skills/search.ts +73 -0
- package/src/commands/skills/show.ts +72 -0
- package/src/commands/skills/validate.test.ts +466 -0
- package/src/commands/skills/validate.ts +227 -0
- package/src/lib/api/skills-client.ts +148 -0
- package/src/program.test.ts +1 -3
- package/src/program.ts +125 -35
- package/src/schemas/config.v1.schema.json +37 -0
- package/src/schemas/generated/api-responses.ts +386 -0
- package/src/schemas/generated/auth.ts +21 -0
- package/src/schemas/generated/index.ts +5 -0
- package/src/schemas/generated/package.ts +29 -0
- package/src/schemas/generated/skill.ts +271 -0
- package/src/utils/config-manager.test.ts +182 -2
- package/src/utils/config-manager.ts +126 -12
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills API client for mpak registry
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
SkillSearchResponse,
|
|
7
|
+
SkillDetail,
|
|
8
|
+
SkillDownloadInfo,
|
|
9
|
+
} from '../../schemas/generated/skill.js';
|
|
10
|
+
|
|
11
|
+
const DEFAULT_REGISTRY_URL = 'https://api.mpak.dev';
|
|
12
|
+
|
|
13
|
+
function getRegistryUrl(): string {
|
|
14
|
+
return process.env.MPAK_REGISTRY_URL || DEFAULT_REGISTRY_URL;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Parse a scoped name into scope and name parts
|
|
19
|
+
* Handles both @scope/name and scope/name formats
|
|
20
|
+
*/
|
|
21
|
+
function parseScopedName(name: string): { scope: string; skillName: string } {
|
|
22
|
+
const normalizedName = name.startsWith('@') ? name.slice(1) : name;
|
|
23
|
+
const [scope, skillName] = normalizedName.split('/');
|
|
24
|
+
if (!scope || !skillName) {
|
|
25
|
+
throw new Error(`Invalid skill name format: ${name}. Expected @scope/name or scope/name`);
|
|
26
|
+
}
|
|
27
|
+
return { scope, skillName };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface SkillSearchOptions {
|
|
31
|
+
q?: string;
|
|
32
|
+
tags?: string;
|
|
33
|
+
category?: string;
|
|
34
|
+
surface?: string;
|
|
35
|
+
sort?: 'downloads' | 'recent' | 'name';
|
|
36
|
+
limit?: number;
|
|
37
|
+
offset?: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Search for skills in the registry
|
|
42
|
+
*/
|
|
43
|
+
export async function searchSkills(options: SkillSearchOptions): Promise<SkillSearchResponse> {
|
|
44
|
+
const baseUrl = getRegistryUrl();
|
|
45
|
+
const params = new URLSearchParams();
|
|
46
|
+
|
|
47
|
+
if (options.q) params.set('q', options.q);
|
|
48
|
+
if (options.tags) params.set('tags', options.tags);
|
|
49
|
+
if (options.category) params.set('category', options.category);
|
|
50
|
+
if (options.surface) params.set('surface', options.surface);
|
|
51
|
+
if (options.sort) params.set('sort', options.sort);
|
|
52
|
+
if (options.limit) params.set('limit', options.limit.toString());
|
|
53
|
+
if (options.offset) params.set('offset', options.offset.toString());
|
|
54
|
+
|
|
55
|
+
const url = `${baseUrl}/v1/skills/search?${params.toString()}`;
|
|
56
|
+
|
|
57
|
+
const response = await fetch(url, {
|
|
58
|
+
headers: { Accept: 'application/json' },
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
const text = await response.text();
|
|
63
|
+
throw new Error(`Search failed (${response.status}): ${text}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return response.json() as Promise<SkillSearchResponse>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Get skill details from the registry
|
|
71
|
+
*/
|
|
72
|
+
export async function getSkillDetails(name: string): Promise<SkillDetail> {
|
|
73
|
+
const baseUrl = getRegistryUrl();
|
|
74
|
+
const { scope, skillName } = parseScopedName(name);
|
|
75
|
+
|
|
76
|
+
// Server expects: /v1/skills/@scope/name
|
|
77
|
+
const url = `${baseUrl}/v1/skills/@${scope}/${skillName}`;
|
|
78
|
+
|
|
79
|
+
const response = await fetch(url, {
|
|
80
|
+
headers: { Accept: 'application/json' },
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
if (response.status === 404) {
|
|
85
|
+
throw new Error(`Skill not found: ${name}`);
|
|
86
|
+
}
|
|
87
|
+
const text = await response.text();
|
|
88
|
+
throw new Error(`Failed to get skill details (${response.status}): ${text}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return response.json() as Promise<SkillDetail>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get download info for a skill
|
|
96
|
+
*/
|
|
97
|
+
export async function getSkillDownloadInfo(
|
|
98
|
+
name: string,
|
|
99
|
+
version?: string
|
|
100
|
+
): Promise<SkillDownloadInfo> {
|
|
101
|
+
const baseUrl = getRegistryUrl();
|
|
102
|
+
const { scope, skillName } = parseScopedName(name);
|
|
103
|
+
|
|
104
|
+
// Server expects: /v1/skills/@scope/name/download or /v1/skills/@scope/name/versions/x.y.z/download
|
|
105
|
+
const versionPath = version ? `/versions/${version}` : '';
|
|
106
|
+
const url = `${baseUrl}/v1/skills/@${scope}/${skillName}${versionPath}/download`;
|
|
107
|
+
|
|
108
|
+
const response = await fetch(url, {
|
|
109
|
+
headers: { Accept: 'application/json' },
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
if (response.status === 404) {
|
|
114
|
+
throw new Error(`Skill not found: ${name}${version ? `@${version}` : ''}`);
|
|
115
|
+
}
|
|
116
|
+
const text = await response.text();
|
|
117
|
+
throw new Error(`Failed to get download info (${response.status}): ${text}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return response.json() as Promise<SkillDownloadInfo>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Download a skill bundle
|
|
125
|
+
*/
|
|
126
|
+
export async function downloadSkillBundle(
|
|
127
|
+
downloadUrl: string,
|
|
128
|
+
expectedSha256?: string
|
|
129
|
+
): Promise<Buffer> {
|
|
130
|
+
const response = await fetch(downloadUrl);
|
|
131
|
+
|
|
132
|
+
if (!response.ok) {
|
|
133
|
+
throw new Error(`Download failed (${response.status})`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
137
|
+
|
|
138
|
+
// Verify SHA256 if provided
|
|
139
|
+
if (expectedSha256) {
|
|
140
|
+
const { createHash } = await import('crypto');
|
|
141
|
+
const hash = createHash('sha256').update(buffer).digest('hex');
|
|
142
|
+
if (hash !== expectedSha256) {
|
|
143
|
+
throw new Error(`SHA256 mismatch: expected ${expectedSha256}, got ${hash}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return buffer;
|
|
148
|
+
}
|
package/src/program.test.ts
CHANGED
|
@@ -9,9 +9,7 @@ describe('createProgram', () => {
|
|
|
9
9
|
|
|
10
10
|
it('should have a description', () => {
|
|
11
11
|
const program = createProgram();
|
|
12
|
-
expect(program.description()).toBe(
|
|
13
|
-
'CLI for downloading MCPB bundles from the package directory'
|
|
14
|
-
);
|
|
12
|
+
expect(program.description()).toBe('CLI for MCP bundles and Agent Skills');
|
|
15
13
|
});
|
|
16
14
|
|
|
17
15
|
it('should have version option', () => {
|
package/src/program.ts
CHANGED
|
@@ -1,26 +1,66 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { getVersion } from './utils/version.js';
|
|
3
|
+
import { handleUnifiedSearch } from './commands/search.js';
|
|
3
4
|
import { handleSearch } from './commands/packages/search.js';
|
|
4
5
|
import { handleShow } from './commands/packages/show.js';
|
|
5
6
|
import { handlePull } from './commands/packages/pull.js';
|
|
6
7
|
import { handleRun } from './commands/packages/run.js';
|
|
7
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
handleConfigSet,
|
|
10
|
+
handleConfigGet,
|
|
11
|
+
handleConfigList,
|
|
12
|
+
handleConfigClear,
|
|
13
|
+
} from './commands/config.js';
|
|
14
|
+
import {
|
|
15
|
+
handleSkillValidate,
|
|
16
|
+
handleSkillPack,
|
|
17
|
+
handleSkillSearch,
|
|
18
|
+
handleSkillShow,
|
|
19
|
+
handleSkillPull,
|
|
20
|
+
handleSkillInstall,
|
|
21
|
+
handleSkillList,
|
|
22
|
+
} from './commands/skills/index.js';
|
|
8
23
|
|
|
9
24
|
/**
|
|
10
25
|
* Creates and configures the CLI program
|
|
11
26
|
*
|
|
12
|
-
*
|
|
27
|
+
* Command structure:
|
|
28
|
+
* - mpak search <query> - Unified search (bundles + skills)
|
|
29
|
+
* - mpak bundle <command> - MCP bundle commands
|
|
30
|
+
* - mpak skill <command> - Agent skill commands
|
|
31
|
+
* - mpak config <command> - Configuration commands
|
|
13
32
|
*/
|
|
14
33
|
export function createProgram(): Command {
|
|
15
34
|
const program = new Command();
|
|
16
35
|
|
|
17
36
|
program
|
|
18
37
|
.name('mpak')
|
|
19
|
-
.description('CLI for
|
|
38
|
+
.description('CLI for MCP bundles and Agent Skills')
|
|
20
39
|
.version(getVersion(), '-v, --version', 'Output the current version');
|
|
21
40
|
|
|
22
|
-
//
|
|
41
|
+
// ==========================================================================
|
|
42
|
+
// Unified search (bundles + skills)
|
|
43
|
+
// ==========================================================================
|
|
44
|
+
|
|
23
45
|
program
|
|
46
|
+
.command('search <query>')
|
|
47
|
+
.description('Search bundles and skills')
|
|
48
|
+
.option('--type <type>', 'Filter by type (bundle, skill)')
|
|
49
|
+
.option('--sort <field>', 'Sort by: downloads, recent, name')
|
|
50
|
+
.option('--limit <number>', 'Limit results', parseInt)
|
|
51
|
+
.option('--offset <number>', 'Pagination offset', parseInt)
|
|
52
|
+
.option('--json', 'Output as JSON')
|
|
53
|
+
.action(async (query, options) => {
|
|
54
|
+
await handleUnifiedSearch(query, options);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// ==========================================================================
|
|
58
|
+
// Bundle namespace (MCP bundles)
|
|
59
|
+
// ==========================================================================
|
|
60
|
+
|
|
61
|
+
const bundle = program.command('bundle').description('MCP bundle commands');
|
|
62
|
+
|
|
63
|
+
bundle
|
|
24
64
|
.command('search <query>')
|
|
25
65
|
.description('Search public bundles')
|
|
26
66
|
.option('--type <type>', 'Filter by server type (node, python, binary)')
|
|
@@ -32,8 +72,7 @@ export function createProgram(): Command {
|
|
|
32
72
|
await handleSearch(query, options);
|
|
33
73
|
});
|
|
34
74
|
|
|
35
|
-
|
|
36
|
-
program
|
|
75
|
+
bundle
|
|
37
76
|
.command('show <package>')
|
|
38
77
|
.description('Show detailed information about a bundle')
|
|
39
78
|
.option('--json', 'Output as JSON')
|
|
@@ -41,19 +80,9 @@ export function createProgram(): Command {
|
|
|
41
80
|
await handleShow(packageName, options);
|
|
42
81
|
});
|
|
43
82
|
|
|
44
|
-
|
|
45
|
-
program
|
|
46
|
-
.command('info <package>')
|
|
47
|
-
.description('Show detailed information about a bundle (alias for show)')
|
|
48
|
-
.option('--json', 'Output as JSON')
|
|
49
|
-
.action(async (packageName, options) => {
|
|
50
|
-
await handleShow(packageName, options);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// Pull command
|
|
54
|
-
program
|
|
83
|
+
bundle
|
|
55
84
|
.command('pull <package>')
|
|
56
|
-
.description('Download a bundle from the registry
|
|
85
|
+
.description('Download a bundle from the registry')
|
|
57
86
|
.option('-o, --output <path>', 'Output file path')
|
|
58
87
|
.option('--os <os>', 'Target OS (darwin, linux, win32)')
|
|
59
88
|
.option('--arch <arch>', 'Target architecture (x64, arm64)')
|
|
@@ -62,35 +91,96 @@ export function createProgram(): Command {
|
|
|
62
91
|
await handlePull(packageSpec, options);
|
|
63
92
|
});
|
|
64
93
|
|
|
65
|
-
|
|
66
|
-
program
|
|
67
|
-
.command('install <package>')
|
|
68
|
-
.description('Download a bundle from the registry (alias for pull)')
|
|
69
|
-
.option('-o, --output <path>', 'Output file path')
|
|
70
|
-
.option('--os <os>', 'Target OS (darwin, linux, win32)')
|
|
71
|
-
.option('--arch <arch>', 'Target architecture (x64, arm64)')
|
|
72
|
-
.option('--json', 'Output download info as JSON')
|
|
73
|
-
.action(async (packageSpec, options) => {
|
|
74
|
-
await handlePull(packageSpec, options);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Run command
|
|
78
|
-
program
|
|
94
|
+
bundle
|
|
79
95
|
.command('run <package>')
|
|
80
|
-
.description('Run an MCP server from the registry
|
|
96
|
+
.description('Run an MCP server from the registry')
|
|
81
97
|
.option('--update', 'Force re-download even if cached')
|
|
82
98
|
.action(async (packageSpec, options) => {
|
|
83
99
|
await handleRun(packageSpec, options);
|
|
84
100
|
});
|
|
85
101
|
|
|
86
|
-
//
|
|
102
|
+
// ==========================================================================
|
|
103
|
+
// Skill namespace (Agent Skills)
|
|
104
|
+
// ==========================================================================
|
|
105
|
+
|
|
106
|
+
const skill = program.command('skill').description('Agent skill commands');
|
|
107
|
+
|
|
108
|
+
skill
|
|
109
|
+
.command('validate <path>')
|
|
110
|
+
.description('Validate a skill directory against the Agent Skills spec')
|
|
111
|
+
.option('--json', 'Output as JSON')
|
|
112
|
+
.action(async (path, options) => {
|
|
113
|
+
await handleSkillValidate(path, options);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
skill
|
|
117
|
+
.command('pack <path>')
|
|
118
|
+
.description('Create a .skill bundle from a skill directory')
|
|
119
|
+
.option('-o, --output <path>', 'Output file path')
|
|
120
|
+
.option('--json', 'Output as JSON')
|
|
121
|
+
.action(async (path, options) => {
|
|
122
|
+
await handleSkillPack(path, options);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
skill
|
|
126
|
+
.command('search <query>')
|
|
127
|
+
.description('Search skills in the registry')
|
|
128
|
+
.option('--tags <tags>', 'Filter by tags (comma-separated)')
|
|
129
|
+
.option('--category <category>', 'Filter by category')
|
|
130
|
+
.option('--surface <surface>', 'Filter by surface (claude-code, claude-api, claude-ai)')
|
|
131
|
+
.option('--sort <field>', 'Sort by: downloads, recent, name')
|
|
132
|
+
.option('--limit <number>', 'Limit results', parseInt)
|
|
133
|
+
.option('--offset <number>', 'Pagination offset', parseInt)
|
|
134
|
+
.option('--json', 'Output as JSON')
|
|
135
|
+
.action(async (query, options) => {
|
|
136
|
+
await handleSkillSearch(query, options);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
skill
|
|
140
|
+
.command('show <name>')
|
|
141
|
+
.description('Show detailed information about a skill')
|
|
142
|
+
.option('--json', 'Output as JSON')
|
|
143
|
+
.action(async (name, options) => {
|
|
144
|
+
await handleSkillShow(name, options);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
skill
|
|
148
|
+
.command('pull <name>')
|
|
149
|
+
.description('Download a .skill bundle from the registry')
|
|
150
|
+
.option('-o, --output <path>', 'Output file path')
|
|
151
|
+
.option('--json', 'Output as JSON')
|
|
152
|
+
.action(async (name, options) => {
|
|
153
|
+
await handleSkillPull(name, options);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
skill
|
|
157
|
+
.command('install <name>')
|
|
158
|
+
.description('Install a skill to ~/.claude/skills/')
|
|
159
|
+
.option('--force', 'Overwrite existing installation')
|
|
160
|
+
.option('--json', 'Output as JSON')
|
|
161
|
+
.action(async (name, options) => {
|
|
162
|
+
await handleSkillInstall(name, options);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
skill
|
|
166
|
+
.command('list')
|
|
167
|
+
.description('List installed skills')
|
|
168
|
+
.option('--json', 'Output as JSON')
|
|
169
|
+
.action(async (options) => {
|
|
170
|
+
await handleSkillList(options);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// ==========================================================================
|
|
174
|
+
// Config commands (shared for bundles and skills)
|
|
175
|
+
// ==========================================================================
|
|
176
|
+
|
|
87
177
|
const configCmd = program
|
|
88
178
|
.command('config')
|
|
89
179
|
.description('Manage per-package configuration values');
|
|
90
180
|
|
|
91
181
|
configCmd
|
|
92
182
|
.command('set <package> <key=value...>')
|
|
93
|
-
.description('Set config value(s) for a package
|
|
183
|
+
.description('Set config value(s) for a package')
|
|
94
184
|
.action(async (packageName, keyValuePairs) => {
|
|
95
185
|
await handleConfigSet(packageName, keyValuePairs);
|
|
96
186
|
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://mpak.dev/schemas/config.v1.json",
|
|
4
|
+
"title": "mpak CLI Configuration v1",
|
|
5
|
+
"description": "Configuration file for the mpak CLI stored at ~/.mpak/config.json",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["version", "lastUpdated"],
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"version": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"const": "1.0.0",
|
|
13
|
+
"description": "Configuration schema version"
|
|
14
|
+
},
|
|
15
|
+
"lastUpdated": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"format": "date-time",
|
|
18
|
+
"description": "ISO 8601 timestamp of last configuration update"
|
|
19
|
+
},
|
|
20
|
+
"registryUrl": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"format": "uri",
|
|
23
|
+
"description": "Custom registry URL (overrides default https://api.mpak.dev)"
|
|
24
|
+
},
|
|
25
|
+
"packages": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"description": "Per-package configuration values (user_config)",
|
|
28
|
+
"additionalProperties": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"description": "Configuration key-value pairs for a specific package",
|
|
31
|
+
"additionalProperties": {
|
|
32
|
+
"type": "string"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|